zoukankan      html  css  js  c++  java
  • Javascript公共脚本库系列(四) 改进的弹出层脚本

    本文转自:http://www.cnblogs.com/zhangziqiu/archive/2009/02/24/javascriptLibrary-4.html

    一.摘要

    本篇文章并没有为系列文中构造的轻量级脚本库添加新的方法, 而是改进了原有弹出浮动层的方法. 对方法中获取位置的函数重构出来, 为弹出层自动添加iframe遮盖层以实现IE6下遮住<Select>控件. 又放在此系列文章中也是对自己学习过程的一次记录.

    二.关于弹出层无法遮盖select的问题

    在IE6下存在一个Bug: 如果弹出层是一个div, 并且在弹出层下方有一个<select>下拉框控件, 则div无论z-index值如何设置都无法遮盖select控件.如图:

    image

    目前有两种解决办法:

    1.当弹出层出现时隐藏select控件.

    个人认为此方法的效果欠佳, 并且没有通用性.

    2.在弹出层下添加一个一个iframe

    因为在IE6中认为select控件认为是窗口级元素. 所以可以使用同样是窗口级元素的iframe来遮盖住Select控件, 注意需要将iframe的zIndex值设置为大于select控件.

    关于添加iframe的方式有很多种.比如在弹出层里面添加一个宽度为div宽+div边框宽的iframe(为了遮盖弹出层边框), 或者在页面上添加一个透明的iframe并控制firame与弹出层的同步显示等.

    三.改进版ScriptHelper实现方法

    因为我们构建的是通用的轻量级脚本库, 所以我不希望为了使用脚本库还需要在页面上添加特别的iframe元素.而且也不希望在所有的弹出层上都添加一个iframe元素, 因为会增加弹出层的代码.于是通过改进弹出图层showDivCommon和关闭图层closeDivCommon这两个方法实现了动态添加iframe和隐藏iframe.

    实现思路:

    1.为每个弹出层动态的在Body元素上添加一个div, div中包含一个iframe元素. 当弹出层显示时设置iframe的位置和长宽与弹出层相同, zIndex值为弹出层-1, 关闭时弹出层时也隐藏iframe.

    2.iframe和iframe的容器div在第一次弹出时创建, 以后再弹出和关闭不会重新创建.

    3.每一个弹出层都会有一个对应的iframe, 以满足一个页面同时弹出多个弹出层的需求

    实现代码:

    修改后的showDivCommon和closeDivCommon方法:

    //  显示图层,再次调用则隐藏
    /*  参数说明:
    sObj        : 要弹出图层的事件源
    divId       : 要显示的图层ID    
    moveTop     : 手工向下移动的偏移量.不移动则为0(默认).
    moveLeft    : 手工向左移动的距离.不移动则为0(默认).
        
    用法与测试:
    <div><a href="#" onclick="ScriptHelperV2.showDivCommon(this,'testDiv', 20, 20)">事件源</a></div>  
    */
    scriptHelperV2.prototype.showDivCommon = function(sObj, divId, moveTop, moveLeft) {
    
        //取消冒泡事件
        if (typeof (window) != 'undefined' && window != null && window.event != null) {
            window.event.cancelBubble = true;
        }
        else if (ScriptHelperV2.showDivCommon.caller.arguments[0] != null) {
            ScriptHelperV2.showDivCommon.caller.arguments[0].cancelBubble = true;
        }
    
        //参数检测.如果没有传入参数则设置默认值
        if (moveLeft == null) {
            moveLeft = 0;
        }
        if (moveTop == null) {
            moveTop = 0;
        }
    
        var divObj = document.getElementById(divId); //获得弹出图层对象    
        var sObjOffsetTop = 0;      //事件源的垂直距离
        var sObjOffsetLeft = 0;     //事件源的水平距离
    
        var position = this.getPosition(sObj); //获取事件源对象的偏移量
        var myClient = this.getClient();       //获取屏幕大小  
        var myScroll = this.getScroll();       //获取滚动条滚动的举例
        var sWidth = sObj.offsetWidth != null ? parseInt(sObj.offsetWidth) : 0;    //事件源对象的宽度
        var sHeight = sObj.offsetHeight != null ? parseInt(sObj.offsetHeight) : 20; //事件源对象的高度
        var popDivWidth = 0;    //弹出层的宽度
        var popDivHeight = 0;   //弹出层的高度
        var bottomSpace;        //距离底部的距离
    
        var iframeDivId = "tempIframeDiv" + divId;  //iframe所在div的id
        var iframeId = "tempIframe" + divId;        //iframe的id
        var iframeDiv = document.getElementById(iframeDivId); //iframe所在div对象
        var iframe = document.getElementById(iframeId); //iframe对象
    
    
        if (divObj.style.display.toLowerCase() != "none") {
            //隐藏图层
            divObj.style.display = "none";
            //隐藏iframe
            if (iframe != null) {
                iframe.style.display = "none";
            }
    
            if (iframeDiv != null) {
                iframeDiv.style.display = "none";
            }
        }
        else {
            if (sObj == null) {
                alert("事件源对象为null");
                return false;
            }
    
            //先显示图层,才能获取到弹出层的长宽
            divObj.style.display = "block";
            popDivWidth = divObj.offsetWidth != null ? parseInt(sObj.offsetWidth) : 0;      //弹出层宽度
            popDivHeight = divObj.offsetHeight != null ? parseInt(divObj.offsetHeight) : 0;  //弹出层高度
    
            /* 获取距离底部的距离 */
            bottomSpace = parseInt(myClient.clientHeight) - (parseInt(position.OffsetTop) - parseInt(myScroll.scrollTop)) - parseInt(sHeight);
    
            /* 设置图层显示位置 */
            //如果事件源下方空间不足且上方控件足够容纳弹出层,则在上方显示.否则在下方显示
            if (popDivHeight > 0 && bottomSpace < popDivHeight && position.OffsetTop > popDivHeight) {
                divObj.style.top = (parseInt(position.OffsetTop) - parseInt(popDivHeight)).toString() + "px";
            }
            else {
                divObj.style.top = (parseInt(position.OffsetTop) + parseInt(sHeight)).toString() + "px";
    
            }
            divObj.style.left = (parseInt(position.OffsetLeft) - parseInt(moveLeft)).toString() + "px";
    
    
        }
    
        //如果遮盖iframe层不存在则创建
        if (iframe == null) {
            //ie6下使用dom添加节点后无法控制某些属性, 所以将iframe放在一个div中,这样才可以用写html的方式添加. 
            var tempIframeDiv = document.createElement("div");
            tempIframeDiv.setAttribute("id", iframeDivId);
            document.body.appendChild(tempIframeDiv);
    
            var iframeString = "<iframe id=\"" + iframeId + "\" style=\"position: absolute; display:none; border-0px;\"></iframe>";
            tempIframeDiv.innerHTML = iframeString;
            iframe = document.getElementById(iframeId);
            iframeDiv = document.getElementById(iframeDivId);
        }
        //使用遮盖层遮住select控件
        if (iframe != null && iframeDiv != null) {
            iframeDiv.style.display = "block";
            iframe.style.top = divObj.style.top;
            iframe.style.left = divObj.style.left;
            iframe.style.width = divObj.offsetWidth.toString() + "px";
            iframe.style.height = divObj.offsetHeight.toString() + "px";
            iframe.style.display = "block";
            iframe.style.zIndex = divObj.style.zIndex - 1;
        }
    
    }
    
    
    //  关闭图层
    /*  参数说明:
    divId        : 要隐藏的图层ID    
        
    用法与测试:
    ScriptHelperV2.closeDivCommon('testDiv');    
    */
    scriptHelperV2.prototype.closeDivCommon = function(divId) {
    
        var iframeDivId = "tempIframeDiv" + divId;  //iframe所在div的id
        var iframeId = "tempIframe" + divId;        //iframe的id
        
        var divObj = document.getElementById(divId); //获得图层对象    
        if (divObj != null) {
            divObj.style.display = "none";
        }
    
        var iframe = document.getElementById(iframeId);
        if (iframe != null) {
            iframe.style.display = "none";
        }
    
        var iframeDiv = document.getElementById(iframeDivId);
        if (iframeDiv != null) {
            iframe.style.display = "none";
        } 
    }

    四. 其他改进

    和本系列文章第一版本的方法比较,  showDivCommon方法还做了如下改进:

    1. 将计算坐标的方法抽象出来:

    //获取对象相对于Body对象的偏移量坐标.需要在Body元素加上position:relative, 并且保证任何父级元素都没有position:relative
    /*  参数说明:
    sObj      : 要弹出图层的事件源
        
    用法与测试: 
    var sObj = document.getElementById("divId");
    var position = ScriptHelperV2.getPosition(sObj);
    var sObjOffsetTop = parseInt(  position.OffsetTop );
    var sObjOffsetLeft = parseInt( position.OffsetLeft );
    */
    scriptHelperV2.prototype.getPosition = function(sObj) {
        var sObjOffsetTop = 0;      //事件源的垂直距离
        var sObjOffsetLeft = 0;     //事件源的水平距离
    
        /* 获取事件源对象的偏移量 */
        var tempObj = sObj; //用于计算事件源坐标的临时对象
        while (tempObj && tempObj.tagName.toUpperCase() != "BODY") {
            sObjOffsetTop += tempObj.offsetTop;
            sObjOffsetLeft += tempObj.offsetLeft;
            tempObj = tempObj.offsetParent;
        }
        tempObj = null;
        return { OffsetTop: sObjOffsetTop, OffsetLeft: sObjOffsetLeft };
    }

    2.由于经验浅薄, 原以为获取不到对象的高度和宽度,  经过学习发现可以使用OffsetWidth和OffsetHeight获取. 所以进一步规范了showDivCommon的参数.现在只传入两个参数使用时的坐标计算更加正确:

    <a class="cursorHand" onclick="ScriptHelperV2.showDivCommon(this,'subMenu1');">Menu1</a>

    五.实例

    原ScriptHelper实现效果:

    image

    新ScriptHelperV2实现效果:注意已经遮盖住了select控件

    image

    实例代码:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title>ScriptHelper 类测试页面 - ShowDivComon 显示弹出层方法</title>
        <!--<script src="https://files.cnblogs.com/zhangziqiu/ScriptHelper.js" type="text/javascript"></script>-->
        <script src="https://files.cnblogs.com/zhangziqiu/ScriptHelperV2.js" type="text/javascript"></script>
        <style type="text/css">
            .cursorHand { cursor:pointer;}        
        </style>  
    </head>
    <body  style="position:relative;">
        <div style="height:300px;"></div>
        <!-- Main Menu -->
        <div >
            <a class="cursorHand" onclick="ScriptHelperV2.showDivCommon(this,'subMenu1');">Menu1</a>
        </div>
        
        <div>
            <select id="Select1" style="z-index:1;">
                <option>123</option>
                <option>456</option>
            </select>
        </div>
        
        <!-- Sub Menu 1 -->
        <div id="subMenu1" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; margin:0px; padding:5px; 200px;z-index:100;">
            <div>SubMent-1</div>
            <div>SubMent-2</div>
            <div>SubMent-3</div>
            <div>SubMent-4</div>
            <div>SubMent-5</div>
            <div>SubMent-6</div>
        </div>
       </body>
    </html>

    六.打包下载地址

    https://files.cnblogs.com/zhangziqiu/TestScriptHelper_ShowDivComon.rar

    javascript文件下载地址:

    https://files.cnblogs.com/zhangziqiu/ScriptHelperV2.js

    七.相关经验和技巧

    • 一个li对象的width设置为100px或者li的容器ul的width为100px, 在firefox下, li的offsetWidth永远为100, 超出的内容部分不会自动撑开li, 即使设置了overflow:visible仍然只是在li外部显示超出内容. 解决办法是可以li内再增加一个span对象放置内容文字, 这时获取span的offsetWidth为内容的长度而不是li的长度.
    • 使用document.createElement方法创建的对象,在IE6下虽然可以获取到对象, 但是无法再设置他的宽度和高度. 也就是说createElement在IE和FF下均可用, 但是要想动态创建一个标签并且设置他的宽高,比如一个<iframe>, 可以使用写入HTML代码的方式,写入后可以获取对象并设置他的宽度和高度.
    • 一个div,里面有一个iframe, 关闭时一定要先关闭iframe再关闭div, 否则在ie6中iframe会无法关闭.

    八.总结

    这篇文章没有太多技术含量, 高手们请见谅. 在改进中我学习到了新的知识.希望能和鸟儿们一起进步.

    作者:张子秋
    出处:http://www.cnblogs.com/zhangziqiu/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Java异常处理和设计
    一次qps测试实践
    Alternate Task UVA
    Just Another Problem UVA
    Lattice Point or Not UVA
    Play with Floor and Ceil UVA
    Exploring Pyramids UVALive
    Cheerleaders UVA
    Triangle Counting UVA
    Square Numbers UVA
  • 原文地址:https://www.cnblogs.com/weekend001/p/1564759.html
Copyright © 2011-2022 走看看