點擊圖中的"航空公司"後,會在"航空公司"下面彈出浮動層.
在網上彈出框的腳本相當多, 而且還有各種第三方JS框架可供我們使用.但是其中有的腳本過於簡單,僅僅粗略的實現彈出效果而忽略了靈活性,通用性和跨浏覽器特性. 使用JS框架又有些殺雞用牛刀.所以在收集整理了一些資料後, 寫出了下文中的ScriptHelper類的彈出層方法.
主要特點有:
支持多浏覽器
使用面向對象方法封裝
使用簡單,通用性強.
將計算位置等函數進行提取, 所有的相關函數都可以單獨調用, 可根據具體項目繼續二次開發.
三.腳本方法
下面我先將腳本方法貢獻出來,然後舉例如何使用. 最後講解腳本的原理.
復制代碼 代碼如下:
/* ==================== ScriptHelper 開始 ==================== */
/* scriptHelper 腳本幫助對象.
創建人: ziqiu.zhang 2008.3.5
添加函數:
getScroll():得到鼠標滾過的距離-兼容XHTML
getClient():得到浏覽器當前顯示區域的大小-兼容XHTML
showDivCommon():顯示圖層.
使用舉例:
<div id="testDiv" style="display:none; position:absolute; border:1px #000000;">我是測試圖層我是測試圖層</div>
<div style="width:400px; text-align:center;"><div><a href="#" onclick="ScriptHelper.showDivCommon(this,'testDiv', 20, 70)">事件源</a></div></div>
*/
function scriptHelper()
{
}
// 得到鼠標滾過的距離 scrollTop 與 scrollLeft
/* 用法與測試:
var myScroll = getScroll();
alert("myScroll.scrollTop:" + myScroll.scrollTop);
alert("myScroll.scrollLeft:" + myScroll.scrollLeft);
*/
scriptHelper.prototype.getScroll = function ()
{
var scrollTop = 0, scrollLeft = 0;
scrollTop = (document.body.scrollTop > document.documentElement.scrollTop)? document.body.scrollTop:document.documentElement.scrollTop;
if( isNaN(scrollTop) || scrollTop <0 ){ scrollTop = 0 ;}
scrollLeft = (document.body.scrollLeft > document.documentElement.scrollLeft )? document.body.scrollLeft:document.documentElement.scrollLeft;
if( isNaN(scrollLeft) || scrollLeft <0 ){ scrollLeft = 0 ;}
return { scrollTop:scrollTop, scrollLeft: scrollLeft};
}
// 得到浏覽器當前顯示區域的大小 clientHeight 與 clientWidth
/* 用法與測試:
var myScroll = getScroll();
alert("myScroll.sTop:" + myScroll.sTop);
alert("myScroll.sLeft:" + myScroll.sLeft);
*/
scriptHelper.prototype.getClient = function ()
{
//判斷頁面是否符合XHTML標准
var isXhtml = true;
if( document.documentElement == null || document.documentElement.clientHeight <= 0)
{
if( document.body.clientHeight>0 )
{
isXhtml = false;
}
}
this.clientHeight = isXhtml?document.documentElement.clientHeight:document.body.clientHeight;
this.clientWidth = isXhtml?document.documentElement.clientWidth:document.body.clientWidth;
return {clientHeight:this.clientHeight,clientWidth:this.clientWidth};
}
// 顯示圖層,再次調用則隱藏
/* 參數說明:
sObj : 要彈出圖層的事件源
divId : 要顯示的圖層ID
sObjHeight : 事件源的高度,默認為20.需要手工傳入是因為對於由於事件源對象可能是各種HTML元素,有些元素高度的計算無法跨浏覽器通用.
moveLeft : 手工向左移動的距離.不移動則為0(默認).
divObjHeight: 彈出層的高度.如果傳入大於0的此參數, 則當事件源下方空間不足時,在事件源上方彈出層.如果不傳此參數則一直在事件源下方彈出.
用法與測試:
<div><a href="#" onclick="ScriptHelper.showDivCommon(this,'testDiv', 20, 20)">事件源</a></div>
*/
scriptHelper.prototype.showDivCommon = function (sObj,divId, sObjHeight, moveLeft, divObjHeight)
{
//取消冒泡事件
if( typeof(window)!='undefined' && window != null && window.event != null )
{
window.event.cancelBubble = true;
}
else if( ScriptHelper.showDivCommon.caller.arguments[0] != null )
{
ScriptHelper.showDivCommon.caller.arguments[0].cancelBubble = true;
}
//參數檢測.如果沒有傳入參數則設置默認值
if( moveLeft == null )
{
moveLeft = 0;
}
if( sObjHeight == null )
{
sObjHeight = 20;
}
if(divObjHeight == null)
{
divObjHeight = 0;
}
var divObj = document.getElementById(divId); //獲得圖層對象
var sObjOffsetTop = 0; //事件源的垂直距離
var sObjOffsetLeft = 0; //事件源的水平距離
var myClient = this.getClient();
var myScroll = this.getScroll();
var sWidth = sObj.width; //事件源對象的寬度
var sHeight = sObjHeight; //事件源對象的高度
var bottomSpace; //距離底部的距離
/* 獲取事件源控件的高度和寬度.*/
if( sWidth == null )
{
sWidth = 100;//無法獲取則為100
}
else
{
sWidth = sWidth + 1; //留出1px的距離
}
if( divObj.style.display.toLowerCase() != "none" )
{
//隱藏圖層
divObj.style.display = "none";
}
else
{
if( sObj == null )
{
alert("事件源對象為null");
return false;
}
/* 獲取事件源對象的偏移量 */
var tempObj = sObj; //用於計算事件源坐標的臨時對象
while( tempObj && tempObj.tagName.toUpperCase() != "BODY" )
{
sObjOffsetTop += tempObj.offsetTop;
sObjOffsetLeft += tempObj.offsetLeft;
tempObj = tempObj.offsetParent;
}
tempObj = null;
/* 獲取距離底部的距離 */
bottomSpace = parseInt(myClient.clientHeight) - ( parseInt(sObjOffsetTop) - parseInt(myScroll.scrollTop)) - parseInt(sHeight);
/* 設置圖層顯示位置 */
//如果事件源下方空間不足且上方控件足夠容納彈出層,則在上方顯示.否則在下方顯示
if( divObjHeight>0 && bottomSpace < divObjHeight && sObjOffsetTop >divObjHeight )
{
divObj.style.top = ( parseInt( sObjOffsetTop ) - parseInt( divObjHeight ) - 10).toString() + "px";
}
else
{
divObj.style.top = ( parseInt( sObjOffsetTop ) + parseInt( sHeight ) ).toString() + "px";
}
divObj.style.left = ( parseInt( sObjOffsetLeft ) - parseInt( moveLeft ) ).toString() + "px";
divObj.style.display="block";
}
}
// 關閉圖層
/* 參數說明:
divId : 要隱藏的圖層ID
用法與測試:
ScriptHelper.closeDivCommon('testDiv');
*/
scriptHelper.prototype.closeDivCommon = function (divId)
{
//
var divObj = document.getElementById(divId); //獲得圖層對象
if( divObj != null )
{
divObj.style.display = "none";
}
}
//建立scriptHelper類的一個實例對象.全局使用.
var ScriptHelper = new scriptHelper();
/* ==================== ScriptHelper 結束 ==================== */
四.使用舉例
接下來我們創建HTML頁面演示如何使用此腳本.此實例是一個菜單,當點擊時顯示子菜單圖層.
1.引用腳本文件
將上面的代碼保存在ScriptHelper.js文件中.在頁面中添加引用:
<script src="http://files.cnblogs.com/zhangziqiu/ScriptHelper.js" type="text/javascript" defer="defer"></script>
2.編寫子菜單
先編寫兩個子菜單圖層.
復制代碼 代碼如下:
<!-- Sub Menu 1 -->
<div id="subMenu1" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; margin:0px; padding:5px; height:100px;">
<div>1-1</div>
<div>1-2</div>
</div>
<!-- Sub Menu 2 -->
<div id="subMenu2" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; padding:5px;" >
<div>2-1</div>
<div>2-2</div>
</div>
對於子菜單, 最重要的就是要設置兩個樣式:position和display.
position:absolute 讓此圖層能夠精確定位顯示.從而控制他的顯示位置.
display:none 讓圖層在加載時不顯示.
3.編寫主菜單
主菜單代碼如下:
復制代碼 代碼如下:
<!-- Main Menu -->
<div >
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu1', 20, 0, 100)">Menu1</a>
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu2', 20, 0)">Menu2</a>
<a class="cursorHand" href="#">NoSubMenu</a>
</div>
我們創建了三個菜單.其中Menu1和Menu2擁有子菜單, NoSubMenu沒有子菜單.
我們使用了a元素創建菜單對象, 但是因為沒有為其添加href屬性,所以默認情況下鼠標放上去不會變成hand圖形.需要為其添加樣式cursorHand,次樣式的代碼如下:
<style type="text/css">
.cursorHand { cursor:pointer;}
</style>
最關鍵的是為菜單添加的onclick事件, 此事件調用ScriptHelper.showDivCommon方法用於顯示圖層.
方法第一個參數值為this表示將事件源對象傳入, 在函數中會根據事件源計算顯示位置.
方法第二個參數表示彈出圖的Id
方法第三個參數是可選參數, 用於設置向下的偏移量.因為我們計算的位置是"<a>Menu1</a>"這個元素的左上角坐標.需要設置一個向下的偏移量.一般設置為事件源的高度,默認為20px.
方法第四個參數是可選參數,用於設置向左的偏移量.原因同上.默認為0px;
方法第五個參數是可選參數,需要傳入彈出層的高度.如果使用了此屬性則彈出層可能彈出在事件源上方.不傳遞此屬性則始終在事件源下方彈出圖層.
4.效果與完整代碼
完整實例代碼如下:
復制代碼 代碼如下:
<!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 類測試頁面</title>
<script src="http://files.cnblogs.com/zhangziqiu/ScriptHelper.js" type="text/javascript" defer="defer"></script>
<style type="text/css">
.cursorHand { cursor:pointer;}
</style>
</head>
<body style="position:relative;">
<div style="height:200px;"></div>
<!-- Main Menu -->
<div >
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu1', 20, 0, 100)">Menu1</a>
<a class="cursorHand" onclick="ScriptHelper.showDivCommon(this,'subMenu2', 20, 0)">Menu2</a>
<a class="cursorHand" href="#">NoSubMenu</a>
</div>
<!-- Sub Menu 1 -->
<div id="subMenu1" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; margin:0px; padding:5px; height:100px;">
<div>1-1</div>
<div>1-2</div>
</div>
<!-- Sub Menu 2 -->
<div id="subMenu2" style="position:absolute; display:none; background-color:#D7EFCD; border:solid 1px #000000; padding:5px;" >
<div>2-1</div>
<div>2-2</div>
</div>
</body>
</html>
五.注意事項:
1.要給Body元素加上position:relative樣式:
<body style="position:relative;">
不增加的話在IE6下有時會出現無法精確定位事件源的情況.比如在menu的<div>上添加幾個<br/>,則彈出層的位置就發生錯誤了.
如果在Body元素上增加此樣式仍然彈出位置錯誤,則請在事件源對象的容器元素中也添加此樣式
2.不傳遞最後一個參數則彈出層只在事件源下面彈出.否則將會計算事件源底部的舉例, 如果底部控件不足並且上部控件充足,則彈出層顯示在事件源上方.
3.在頁面上要添加DOCTYPE元素.不添加的話很可能在某些浏覽器中出現錯誤.有關DOCTYPE的作用,請查看下面的文章:
DOCTYPE元素解析
六.總結
兼容多浏覽器真的是一件讓人頭疼的事情.我估計此函數還是會有問題.本來想寫腳本分析的, 但是在寫作的時候又發現了一些Bug並且進行了修正.兼容來兼容去最後把自己兼容暈了.其實如果一個項目能使用腳本庫將會是一個很好的選擇.本系列文章只是希望構建一個輕量級的腳本類庫.大家使用中有任何問題希望多多交流, 一起打造簡單易用的腳本庫!