上下div高度动态自适应--另类处理方案

     这段时间在工作中遇到一个看似较为棘手的问题。问题描述:查询报表页面分为上下两部分,上部分为条件输入区域,下部分为报表展示区域。客户要求做到默认满屏(但要动态适应不同的窗体大小,也就是浏览器窗体用户会手动改变其大小),但上部分条件输入区域有动态变化高度的现象。

     在遇到上述问题,您是否第一反应就是利用window的onresize事件,做尺寸的动态调整。但是条件输入区域某个按钮动态改变了上部分的高度时,我们又应该如何呢。是否有统一的处理方案呢。今儿本人就把我自己的想法和测试提供出来,供大家参考,有疑问或建议欢迎交流和沟通。

一、上代码

闲话少说,上代码。首先本人为了处理与IE的兼容性,对现代浏览器,IE浏览器做了区别对待。然后提供了一个工厂类以供使用。

1.1、 现代浏览器的实现

/**
        * 现代浏览器处理方案
        */
        function RptAutoHeightForModernBrower(context){
            this.context = context;
            this.$object = null;
        }
        var mPt = RptAutoHeightForModernBrower.prototype;
        mPt.init = function(){
            var object = document.createElement('iframe'), self = this; //object在ie11上onload方法不能执行
            //区元素,绝对定位(父级必须是相对定位,否则参考到body了),四个为0,width、height为100%让其宽、高与父级相同,pointer-events:none(不接受鼠标事件)z-index:层级最低。
            object.onload = function(){ 
                var context = this;
                this.contentDocument.defaultView.addEventListener('resize', function(){ 
                    self.context.onResize(context.clientHeight);
                });
            }
            object.setAttribute('style', 'display:block; position:absolute; border:0px; visibility: hidden; left:0px; right: 0px; top: 0px; bottom: 0px; pointer-events: none; z-index: -1; overflow:hidden; width: 100%; height: 100%; opacity:0;');
            //object.type = "text/html";
            object.src = "about:blank";
            this.context.$header.appendChild(object);
            this.$object = object;
            //先触发一次 
            this.context.onResize(this.context.$header.clientHeight);
            //window.resize事件
            window.onresize = function(){
                self.context.onResize(self.context.$header.clientHeight);
            }
        }
        mPt.dispose = function(){
            this.$object.contentDocument.defaultView.removeEventListener('resize');
            this.context.$header.removeChild(this.$object);
        }

     在此处,为了做到兼容IE11(因为Ie11不支持attacheEvent方法,所以也会被判断为现代浏览器),本人创建的DOM,不是使用的object而是使用的iframe,因为在IE下object的onload事件不能触发,而iframe的可能有;并且iframe的边框一定要去掉,否则影响判断。

1.2、ie浏览器的实现

/**
        * ie的处理方案
        */
        function RptAutoHeightForIE(context){
            this.context = context;
        }
        var iePt = RptAutoHeightForIE.prototype;
        iePt.init = function(){
            var self = this;
            this.context.$header.attachEvent('onresize', function(){
                self.context.onResize(window.event.srcElement.clientHeight);
            });
            this.context.onResize(this.context.$header.clientHeight);
            //window.resize事件
            window.onresize = function(){
                self.context.onResize(self.context.$header.clientHeight);
            }
        }
        iePt.dispose = function(){
            this.context.$header.detachEvent('onresize');
        }

     IE浏览器的实现相对简单,因为IE环境下的div天身支持onresize事件。

1.3、工厂类

//处理高度自适应的Factory
        function RptAutoHeightFactory(opts){
            this.opts = opts || {};
            this.$wrap = this.opts.wrap || document.getElementsByClassName('rpt-wrap')[0];
            this.$header = this.opts.header || this.$wrap.getElementsByClassName('rpt-header')[0];
            this.$cont = this.opts.cont || this.$wrap.getElementsByClassName('rpt-cont')[0];
            var cxt = {
                $header: this.$header,
                onResize: this.resize()
            };
            this.diffVal = 0;
            this.realize = document.attachEvent 
                ? new RptAutoHeightForIE(cxt) 
                : new RptAutoHeightForModernBrower(cxt);
        }
        var pt = RptAutoHeightFactory.prototype;
        pt.init = function(){
            var bTop = this.getStyle(this.$header, "border-top-width");
            var bBottom = this.getStyle(this.$header, "border-bottom-width");
            bTop = parseInt(bTop.replace('px', ''), 10);
            bBottom = parseInt(bBottom.replace('px', ''), 10);
            this.diffVal += bTop + bBottom;
            
            var bTop = this.getStyle(this.$cont, "border-top-width");
            var bBottom = this.getStyle(this.$cont, "border-bottom-width");
            bTop = parseInt(bTop.replace('px', ''), 10);
            bBottom = parseInt(bBottom.replace('px', ''), 10);
            this.diffVal += bTop + bBottom;
            
            this.realize.init(); 

        }
        pt.resize = function(){
            var $cont = this.$cont, self = this;
            return function(headerHeight){
                var dist = self.getMaxHeight() - headerHeight - self.diffVal;
                if(dist > 1 ){
                    $cont.style.height = dist +'px'; //加单位,是为了兼容ie
                }
            }
        }
        pt.getHeight = function(dom){
            var height = dom.clientHeight;            
            return height;
        }
        pt.getStyle = function(dom, key){
            if(dom.currentStyle){
                return dom.currentStyle[key];
            }else if(window.getComputedStyle){
                return window.getComputedStyle(dom, null)[key];
            }
        }
        pt.getMaxHeight = function(){
            return document.documentElement.clientHeight || document.body.clientHeight;
        }

      此处本人在获取style的属性值,使用了getComputedStyle和currentStyle实现的,这民是标准的方法。

1.4、这样使用

js代码:

var irow = 2;
        function addRow(){
            var parent = document.getElementsByClassName('rpt-header')[0];
            var p = document.createElement('p');
            p.innerHTML = "<p>添加第" + irow++ + "行记录</p>";
            parent.appendChild(p);
        }

        var autoHeightFactory = new RptAutoHeightFactory();
        autoHeightFactory.init();

html代码:

<div class="rpt-wrap">
        <div class="rpt-header">
            <button type="button" onclick="addRow()">添加</button>
            <p>第一行内容</p>
        </div>
        <div class="rpt-cont">
        </div>
    </div>

css代码:

html, body{
            margin: 0px;
            padding: 0px;
            height: 100%;
        }
        .rpt-wrap{
            height: inherit;
            overflow: hidden;
        }
        .rpt-header{
            border: 1px solid gray;
            position: relative;
            
        }
        .rpt-cont{
            border: 1px solid red;
        }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术墨客

React学习(3)——列表、键值与表单 原

    例子中使用map方法将每个元素的值*2,最后得到的数组为:[2, 4, 6, 8, 10]。在React中,处理组件数组的方式与之类似。

17230
来自专栏超然的博客

react小结

在react中,父组件给子组件传递数据时,就是以上的方式,通过给子组件设置props,子组件获取props中的值便可完成数据传递。 

9810
来自专栏柠檬先生

Reactjs 入门基础(三)

State 和 Props 以下实例演示了如何在应用中组合使用 state 和 props 。我们可以在父组件中设置 state, 并通过在子组件上使用 pro...

21090
来自专栏云瓣

从 0 到 1 实现 React 系列 —— JSX 和 Virtual DOM

看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/...)

11910
来自专栏九彩拼盘的叨叨叨

jQuery 最佳实践(译)

原文 http://shichuan.github.io/javascript-patterns/#jquery-patterns

7930
来自专栏C/C++基础

Linux命令(27)——echo命令

使用-e选项时,若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:

14930
来自专栏更流畅、简洁的软件开发方式

表单控件续(1)——应用接口来简化和分散代码

上次有点仓促,有几个地方没有明确。 后者是整个流程,前者是其中的一个步骤,是一个简单的思路说明,其中前三段代码都是表单控件里面的。 2、我要写的是一个表单控...

20690
来自专栏练小习的专栏

绝对定位bottom值为0的位置问题

有一个position值为absolute的div,他的祖先元素里没有任何定位属性,或者他的父元素就是body。 当这个div的bottom值为0的时候,他应...

20860
来自专栏程序员互动联盟

【专业技术】还有人在用Qt开发app嘛?

编者按: 这个世界不缺工程师,但是缺大师。如果在Qt里写个app,传统做法,需要熟悉API,熟悉C++,熟悉Qt本身的实现,同时还要熟悉编程环境。 现在出现了一...

65170
来自专栏iKcamp

翻译 | 玩转 React 表单 —— 受控组件详解

原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 译者:小 B0Y 校对者:珂珂君 本...

438100

扫码关注云+社区

领取腾讯云代金券