Javascript公用指令碼庫系列(四) 改進的彈出層指令碼

來源:互聯網
上載者:User
文章目錄
  • 實現思路:
  • 實現代碼:
本文轉自:http://www.cnblogs.com/zhangziqiu/archive/2009/02/24/javascriptLibrary-4.html一.摘要

本篇文章並沒有為系列文中構造的輕量級指令碼庫添加新的方法, 而是改進了原有彈出浮動層的方法. 對方法中擷取位置的函數重構出來, 為彈出層自動添加iframe遮蓋層以實現IE6下遮住<Select>控制項. 又放在此系列文章中也是對自己學習過程的一次記錄.

二.關於彈出層無法遮蓋select的問題

在IE6下存在一個Bug: 如果彈出層是一個div, 並且在彈出層下方有一個<select>下拉框控制項, 則div無論z-index值如何設定都無法遮蓋select控制項.:

目前有兩種解決辦法:

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-width: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實現效果:

新ScriptHelperV2實現效果:注意已經遮蓋住了select控制項

執行個體代碼:

<!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="http://files.cnblogs.com/zhangziqiu/ScriptHelper.js" type="text/javascript"></script>-->    <script src="http://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; width: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>

 

六.打包

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

javascript檔案:

http://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/
本文著作權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.