对页面中元素的坐标信息的获取一直很困惑,今天在网上发现了一篇写的还不错的文章,翻译出来与大家共享,有什么问题也欢迎提出来:
原文参考:(http://javascript.info/tutorial/coordinates)
元素坐标:
- 浏览器坐标系统
- 使用offsetParent属性获取元素的坐标
- 使用w3c标准属性elem.getBoundingClientRect获取元素的坐标
- 结合以上两种方式,实现兼容浏览器的获取坐标方式
- 摘要
在浏览器中存在两个坐标系统:
- 相对文档——坐标远点在页面的左上角
- 相对可视化窗口——坐标原点在可视窗口的左上角
1. 坐标系统
当页面没有滚动时,窗口和页面共享相同的坐标原点,如下图所示:
滚动后,页面相对可视窗口发生了偏移如下图:
事实上,在这两种坐标系统间相互转化很简单,页面坐标是窗口坐标加上页面滚动偏移
大部分时候,仅仅使用页面坐标,因为他们滚动后维持相同。
2. 使用offsetParent属性获取元素的坐标
元素的坐标是元素左上角的坐标,不幸的是没有一个单一的属性可以获取到它的值,但可以是哟个offsetTop/offsetLeft和offsetParent计算它的值。
一种计算元素的绝对坐标的方式是遍历offsetParent链,并对遍历中的每个定位父元素的offsetLeft/offsetTop求和,如下所示:
1 function getOffsetSum(elem) {
3 var top=0, left=0
5 while(elem) {
7 top = top + parseInt(elem.offsetTop)
9 left = left + parseInt(elem.offsetLeft)
11 elem = elem.offsetParent
13 }
15 return {top: top, left: left}
17 }
但这种方式有两个缺陷:
1. 它存在bug,不同的浏览器存在不同的问题,当考虑边框和滚动的时候会出现问题。
2. 它计算起来很慢,每次都要遍历整个offsetParents链
可以写一个跨浏览器修复bug的方法,但先让我们来看另外一种标准做法,该方法在IE6+,firefox3+ OPera ,和safrari及chrome中也支持
3. 正确的方式:elem.getBoundingClientRect
这个方式在W3C标准下有描述,大多数现代浏览器都支持,包括IE
它返回一个包裹元素的矩形框,这个矩形框以top , left , right , bottom四个属性给出。
这四个数字代表了矩形的左上角和右下角的四个坐标,例如:
1 <input id="brTest" type="button" value="Show button.getBoundingClientRect()" onclick='showRect(this)'/>
2
3 <script>
4 function showRect(elem) { 5 var r = elem.getBoundingClientRect() 6 alert("Top/Left: "+r.top+" / "+r.left) 7 alert("Right/Bottom: "+r.right+" / "+r.bottom) 8 } 9 </script>
这个坐标是相对窗口,而不是相对文档。
让我们来看一个新版本的计算坐标的方式:使用getBoundingClientRect
1 function getOffsetRect(elem) { 2 var box = elem.getBoundingClientRect() 3 var body = document.body 4 var docElem = document.documentElement 5 var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop 6 var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft 7 var clientTop = docElem.clientTop || body.clientTop || 0
8 var clientLeft = docElem.clientLeft || body.clientLeft || 0
9 var top = box.top + scrollTop - clientTop 10 var left = box.left + scrollLeft - clientLeft 11 return { top: Math.round(top), left: Math.round(left) } 12 }
计算步骤如下:
- 获取到包含的矩形框
- 计算页面的滚动,除了IE<9外,所有浏览器都支持pageXOffset / pageYOffset,在IE中,当设置了DOCTYPE时,滚动的值可以通过documentElement获得,否则使用body对象获取。
- 在IE中文档会相对左上角偏移几个像素,需要去掉它,减去clientTop和clientLeft
- 矩形框的坐标加上页面相对窗口滚动的坐标,减去偏移的坐标,就得到了元素相对整个文档的坐标。
4. 跨浏览器兼容的解决方案:
有很多js库结合两种方式,获取元素的坐标:
1 function getOffset(elem) { 2 if (elem.getBoundingClientRect) { 3 return getOffsetRect(elem) 4 } else { // old browser
5 return getOffsetSum(elem) 6 } 7 }