相信搞前端開發的朋友們都遇到過這個問題,網上有很多討論它的文章,但似乎都沒有給出一個很完美的解決方案。本文試圖用傳統的遞歸offsetLeft,offsetTop的方法來獲得元素的絕對坐標,並通過這個過程加深對DOM盒模型的理解,將其中易混淆的屬性如offsetLeft,scrollLeft分辨開來。
1. 支持的瀏覽器
針對目前的情況,支持ie6+, 以及firefox,chrome,opera,safari的最新版本(這里偷個懶,所以具體支持到什么版本沒有測試,但是一般而言,國內使用這些瀏覽器的用戶都會選擇較新的版本,應該沒有問題)。
2. 測試頁面編寫
測試頁面有內嵌的CSS元素,以及引入的Javascript代碼,即getOffset函數。測試頁面有以下幾個元素需要注意,首先就是id為target的元素,它是我們要獲取絕對坐標的元素,它存在一個div元素中,這個div元素隨着測試的進行,它的position是否為靜態,是否又邊框,是否又滾動條會發生變化,從而測試我們函數的健壯性。每次測試的觸發都是通過對id為button的元素單擊完成的,測試完成后,需要一個小元素去證明獲取的是否正確,即id為testResult的元素。id為coord元素也只是起一個坐標指示的作用,您可以忽略它。下面是html文件最終的測試版本,您如果用該文件進行測試,在接下來的每一小節的描述中,您需要自行修改CSS部分。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <title>測試最完整的獲取頁面Dom元素的絕對位置的函數-Get Absolute Positon of DOM Element by Javascript </title> <script type="text/javascript" src="getOffset.js"></script> <style type="text/css"> html, body { margin: 0; padding: 0; } html { } body { min-height: 1200px; border: 10px solid red; margin: 30px; } .wrap1 { background-color: #777; } .wrap2 { background-color: #999; margin-left: 20px; } .wrap3 { background-color: #BBB; margin-left: 20px; padding-left: 10px; height: 400px; width: 400px; } .pos-static { position: static; } .pos-nonstatic { position: relative; left: 50px; top: 10px; } .bd { border: 10px solid yellow; } .non-bd { border:none; } .scrl { overflow: scroll; height: 200px; } .non-scrl { overflow: auto; } #target { background: blue; } #testResult { width: 10px; height: 10px; position:absolute; background-color:green; left:0px; top:0px; z-index: 100; } #coord { width: 10px; height: 210px; position: absolute; left: 200px; top:0px; background: green; z-index: 400; } #seperator { height: 200px; background: white; } </style> </head> <body> <div id="testResult"></div> <div id="coord"></div> <div class="wrap1"> <div class="wrap2 pos-nonstatic"> <div class="wrap3 bd scrl"> <div id="seperator"> </div> <div id="target">My position</div> </div> </div> <h1>--------------------------------------------------</h1> </div> <div id="button" style="border:1px solid;">計算 | getOffset_geetest</div> <div id="result"> </div> <script type="text/javascript"> var button = document.getElementById('button'); var target = document.getElementById('target'); var result = document.getElementById('result'); var testResult = document.getElementById('testResult'); button.onclick = function () { var str = ('Ele屬性: offsetLeft:' + target.offsetLeft + ' offsetTop:' +target.offsetTop + ' scrollLeft:' + target.scrollLeft + ' scrollTop:' +target.scrollTop + '<br />'); var pos = getOffset_geetest_ex(target); str += ('getOffset:' + pos.left + ', ' + pos.top +'<br />'); result.innerHTML = str; testResult.style.left = pos.left + "px"; testResult.style.top = pos.top + "px"; } </script> </body> </html>
3. 最原始的getOffset函數,直接用offsetTop 和 offsetLeft遞
function getOffset(el) { var _x = 0, _y = 0; while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) { _x += el.offsetLeft - el.scrollLeft; _y += el.offsetTop - el.scrollTop; el = el.offsetParent; } return { top: _y, left: _x }; }
4. 測試第一步,target的父元素有邊框外,無滾動,body有邊框,border為10,且body的position為relative。
可以看到初始情況下,用於測試結果的testResult小方塊正好在body的框內。如下圖所示
測試結果如下所示:
|
offsetTop |
最終的top |
offsetLeft |
最終的left |
偏移 |
Chrome |
220 |
210 |
70 |
60 |
√ |
Firefox |
210 |
210 |
60 |
60 |
√ |
Opera |
220 |
210 |
70 |
60 |
√ |
IE(高) |
210 |
210 |
60 |
60 |
√ |
IE(低) |
200 |
210 |
10 |
60 |
√ |
通過上表可以看出,Opera和Chrome瀏覽器的表現很一致,即他們的offsetLeft和offsetTop包含了body元素的邊框大小,而Firefox和ie則沒有包含。ie低版本是因為它的offsetLeft指向了它的父元素(position為static)。如果此時,設置body元素的margin,padding都沒有任何影響。
(待續...)