震惊!获取元素绝对位置竟然还要考虑这个。

157 阅读1分钟

今天正在愉快的敲代码的时候,测试突然给我发来一条消息!(测试发消息准没好事),果然,我的代码又双叒叕出bug了!

下载.jfif

我看看怎么事?

事情是这样的,页面会根据URL上的hash值滚动到对应锚点位置,拿到hash之后获取到id=hash的a标签,然后计算出a标签的offsetTop,直接通过window.scrollTo(0, offsetTop)滚动到对应位置即可。

然后就有问题了,其他a标签都能跳过去,怎么其中一个就是滚动不了呢?通过打印它的offsetTop发现明显不对。

offsetTop 是一个只读属性,返回当前元素相对于 offsetParent 节点顶部边界的偏移像素值。

返回值包含:

  • 元素顶部偏移的像素值,元素的外边距(margin)
  • offsetParent 元素的顶部内边距(padding)、边框(border)及滚动条

注意:  offsetParent 元素是一个指向最近的(指包含层级上的最近)包含该元素的定位元素或者最近的元素。

原来是offsetTop的问题,它不是直接获取到绝对位置,而是返回当前元素相对于 offsetParent 节点顶部边界的偏移像素值。

而我那个问题就是因为这个,a标签的父元素开启了定位,所以获取的值是当前元素相对于 offsetParent 节点顶部边界的偏移像素值,那按这个值滚动肯定是不准确的,通过以下方法改造,获取到了准确的值。

function getElementTop(element){
    let actualTop = element.offsetTop;
    let current = element.offsetParent;

    while (current !== null){
      actualTop += current.offsetTop;
      current = current.offsetParent;
    }

    return actualTop;
  }