获取元素相对浏览器窗口的偏移坐标

元素坐标:

  • 浏览器坐标系统
  • 使用offsetParent属性获取元素的坐标
  • 使用w3c标准属性elem.getBoundingClientRect获取元素的坐标
  • 结合以上两种方式,实现兼容浏览器的获取坐标方式
  • 摘要

*在浏览器中存在两个坐标系统:*

  1. 相对文档——坐标远点在页面的左上角
  2. 相对可视化窗口——坐标原点在可视窗口的左上角

1. 坐标系统

当页面没有滚动时,窗口和页面共享相同的坐标原点,如下图所示:

img

滚动后,页面相对可视窗口发生了偏移如下图:

img

事实上,在这两种坐标系统间相互转化很简单,页面坐标是窗口坐标加上页面滚动偏移

大部分时候,仅仅使用页面坐标,因为他们滚动后维持相同。

2. 使用offsetParent属性获取元素的坐标

元素的坐标是元素左上角的坐标,不幸的是没有一个单一的属性可以获取到它的值,但可以是哟个offsetTop/offsetLeft和offsetParent计算它的值。

img

一种计算元素的绝对坐标的方式是遍历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) }
}

计算步骤如下:

  1. 获取到包含的矩形框
  2. 计算页面的滚动,除了IE<9外,所有浏览器都支持pageXOffset / pageYOffset,在IE中,当设置了DOCTYPE时,滚动的值可以通过documentElement获得,否则使用body对象获取。
  3. 在IE中文档会相对左上角偏移几个像素,需要去掉它,减去clientTop和clientLeft
  4. 矩形框的坐标加上页面相对窗口滚动的坐标,减去偏移的坐标,就得到了元素相对整个文档的坐标。

4. 跨浏览器兼容的解决方案:

有很多js库结合两种方式,获取元素的坐标:

function getOffset(elem) {
    if (elem.getBoundingClientRect) {
        return getOffsetRect(elem)
    } else { // old browser
        return getOffsetSum(elem)
    }
}
posted @ 2020-02-28 10:49  怀心抱素  阅读(1170)  评论(0编辑  收藏  举报