十、坐标
两种坐标系(通过 event 获取):
- 相对于窗口的
clientX/clientY—— 类似于position:fixed,从窗口的顶部/左侧边缘计算而出 - 相对于文档的
pageX/pageY—— 从文档的顶部/左侧边缘计算得出
当页面在最开始时,窗口的左上角与文档的左上角对齐,它们的坐标彼此相等。
当文档移动之后,元素的窗口相对坐标会发生变化,因为元素在窗口中移动,而元素在文档中的相对坐标是保持不变的。
上两张图中表示,当元素滚动了:
pageY —— 元素在文档中的相对坐标是不变的,从文档顶部开始计算
clientY —— 元素在窗口中的相对坐标变化了,因为元素被滚上去了,它越来越靠近窗口顶部
10.1 元素坐标 getBoundingClientRect
elem.getBoundingClientRect()返回最小矩形的窗口坐标、返回元素的大小及其相对于视口的位置。
如果是标准盒子模型,元素的尺寸等于width/height + padding + border-width的总和。如果box-sizing: border-box,元素的的尺寸等于 width/height。
这个矩形将elem作为 DOMRect 类的对象。
主要的DOMRect的属性如下:
- x/y —— 矩形原点相对于窗口的 x/y 坐标
- width/height —— 矩形的 width/height (可以为负)
- top/bottom —— 顶部/底部矩形边缘的坐标
- left/right —— 左/右矩形边缘的 X 坐标
left = xtop = yright = x + widthbottom = y + height
当我们使用getBoundingClientRect获取元素的各坐标时,很有可能我们会获取到:
- 小数
- 负数,例如元素被滚上去之后,y 就是 top,相对于窗口来说就是负的
top/left与x/y从矩形的角度来说很有可能是不一致的,而且 width/height 属性也不一定是正数(虽然一直都会返回正数)。原因是矩形有定向这么一说,如果是左上角开始往下伸展算是正向,那么从右下角往上伸展就是负向。所以矩形的 height/width 就是负数的。
以下就是一个由右下角往上伸展的矩形,它的 width/height 就应该是负数的(矩形角度分析)。那么此时,它的 x/y 就应该在右下角的起点位置,因为那才是矩形的原点。
![]()
坐标的 right/bottom 与 css position 属性不同
我们用css position:fixed让元素根据文档定位后的left/top与getBoundingClientRect获取的left/top是类似的逻辑(如果不滚动的话,抛开单位,值可能相同),但是right/bottom是完全不一样的逻辑。
因为 css 定位中的 right 属性是距右边缘的距离,bottom 是距下边缘的距离。
而坐标的right/bottom永远是按照窗口的左上角开始计算的。
10.2 elementFromPoint(x, y)
对 document.elementFromPoint(x, y) 的调用会返回在窗口坐标 (x, y) 处嵌套最多(the most nested)的元素。
因为它使用的是窗口坐标,所以元素可能会因当前滚动位置而有所不同。
注意:
方法 document.elementFromPoint(x,y) 只对在可见区域内的坐标 (x,y) 起作用。
对于在窗口之外的坐标,elementFromPoint 返回 null
10.3 用于“fixed”的定位
如果我们希望创建一个独立存在于窗口上的元素(即使滚动后也依然存在),那么就可以用 fixed 定位后,再设置元素的 left 或者 top 即可。
下面是一个在button附近创建一个文字提示的例子
html1<style> 2 body { 3 min-height: 2000px; 4 } 5 button { 6 display: block; 7 margin: 0 auto; 8 } 9</style> 10<button id="btn">在我下面创建一个提示信息</button> 11<script> 12 const rect = btn.getBoundingClientRect() 13 const [left, bottom] = [rect.left, rect.bottom] 14 btn.onclick = createMessage 15 function createMessage() { 16 const span = document.createElement('span') 17 span.style.cssText = 'color:red;position:fixed' 18 span.innerHTML = '我是提示信息' 19 span.left = left + 'px' 20 span.bottom = bottom + 'px' 21 document.body.append(span) 22 } 23</script>
在最小高度为 2000px 的页面高度下,提示信息会始终出现在窗口的同一位置上,即使滚动了也是如此。
如果不想要这种效果,可以将fixed改成absolute。
10.4 元素的文档坐标
文档坐标是从文档的左上角开始计算而不是窗口。
在 css 中,窗口坐标对应position:fixed,文档坐标则对应顶部元素的position:absolute
我们可以结合absolute来将元素放到文档的某个位置。
目前我们没有标准的方法可以获取元素的文档坐标。我们可以通过计算:
- 元素的文档坐标 x = 文档水平滚出的部分的宽度 + 元素的窗口水平坐标 x
- 元素的文档坐标 y = 文档垂直滚出的部分的宽度 + 元素的窗口垂直坐标 y
下面的函数是获取元素的文档坐标的函数
javascript1function getCoords(elem) { 2 const rect = elem.getBoundingClientRect() 3 let left = window.pageXOffset + rect.left 4 let right = window.pageXOffset + rect.right 5 let top = window.pageYOffset + rect.top 6 let bottom = window.pageYOffset + rect.bottom 7 return { 8 left, 9 right, 10 top, 11 bottom, 12 } 13}
10.5 小结
页面的任何点都有坐标:
- 元素相对于窗口的坐标可以通过
getBoundingClientRect获取 - 元素相对于文档的坐标可以通过
window.pageXoffset/pageYoffset+getBoundingClientReact获取
如果我们想要让元素相对于窗口调整位置,可以设置 css 属性position:fixed
如果我们想要让元素相对于文档调整位置,可以设置 css 属性position:absolute
