相信搞前端開發的朋友們都遇到過這個問題,網上有很多討論它的文章,但似乎都沒有給出一個很完美的解決方案。本文試圖用傳統的遞歸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都沒有任何影響。
(待續...)
