元素坐標:
- 瀏覽器坐標系統
- 使用offsetParent屬性獲取元素的坐標
- 使用w3c標准屬性elem.getBoundingClientRect獲取元素的坐標
- 結合以上兩種方式,實現兼容瀏覽器的獲取坐標方式
- 摘要
*在瀏覽器中存在兩個坐標系統:*
- 相對文檔——坐標遠點在頁面的左上角
- 相對可視化窗口——坐標原點在可視窗口的左上角
1. 坐標系統
當頁面沒有滾動時,窗口和頁面共享相同的坐標原點,如下圖所示:
滾動后,頁面相對可視窗口發生了偏移如下圖:
事實上,在這兩種坐標系統間相互轉化很簡單,頁面坐標是窗口坐標加上頁面滾動偏移
大部分時候,僅僅使用頁面坐標,因為他們滾動后維持相同。
2. 使用offsetParent屬性獲取元素的坐標
元素的坐標是元素左上角的坐標,不幸的是沒有一個單一的屬性可以獲取到它的值,但可以是喲個offsetTop/offsetLeft和offsetParent計算它的值。
一種計算元素的絕對坐標的方式是遍歷offsetParent鏈,並對遍歷中的每個定位父元素的offsetLeft/offsetTop求和,如下所示:
function getOffsetSum(elem) {
var top=0, left=0
while(elem) {
top = top + parseInt(elem.offsetTop)
left = left + parseInt(elem.offsetLeft)
elem = elem.offsetParent
}
return {top: top, left: left}
}
但這種方式有兩個缺陷:
1. 它存在bug,不同的瀏覽器存在不同的問題,當考慮邊框和滾動的時候會出現問題。
2. 它計算起來很慢,每次都要遍歷整個offsetParents鏈
可以寫一個跨瀏覽器修復bug的方法,但先讓我們來看另外一種標准做法,該方法在IE6+,firefox3+ OPera ,和safrari及chrome中也支持
3. 正確的方式:elem.getBoundingClientRect
這個方式在W3C標准下有描述,大多數現代瀏覽器都支持,包括IE
它返回一個包裹元素的矩形框,這個矩形框以top , left , right , bottom四個屬性給出。
這四個數字代表了矩形的左上角和右下角的四個坐標,例如:
<input id="brTest" type="button" value="Show button.getBoundingClientRect()" onclick='showRect(this)'/>
<script>
function showRect(elem) {
var r = elem.getBoundingClientRect()
alert("Top/Left: "+r.top+" / "+r.left)
alert("Right/Bottom: "+r.right+" / "+r.bottom)
}
</script>
這個坐標是相對窗口,而不是相對文檔。
讓我們來看一個新版本的計算坐標的方式:使用getBoundingClientRect
function getOffsetRect(elem) {
var box = elem.getBoundingClientRect()
var body = document.body
var docElem = document.documentElement
var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop
var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft
var clientTop = docElem.clientTop || body.clientTop || 0
var clientLeft = docElem.clientLeft || body.clientLeft || 0
var top = box.top + scrollTop - clientTop
var left = box.left + scrollLeft - clientLeft
return { top: Math.round(top), left: Math.round(left) }
}
計算步驟如下:
- 獲取到包含的矩形框
- 計算頁面的滾動,除了IE<9外,所有瀏覽器都支持pageXOffset / pageYOffset,在IE中,當設置了DOCTYPE時,滾動的值可以通過documentElement獲得,否則使用body對象獲取。
- 在IE中文檔會相對左上角偏移幾個像素,需要去掉它,減去clientTop和clientLeft
- 矩形框的坐標加上頁面相對窗口滾動的坐標,減去偏移的坐標,就得到了元素相對整個文檔的坐標。
4. 跨瀏覽器兼容的解決方案:
有很多js庫結合兩種方式,獲取元素的坐標:
function getOffset(elem) {
if (elem.getBoundingClientRect) {
return getOffsetRect(elem)
} else { // old browser
return getOffsetSum(elem)
}
}