偏移顶部在jquery2和jquery3中表现得很奇怪

时间:2017-01-24 13:26:34

标签: jquery html

在第一个演示中,我使用jquery 2.1.1并在Chrome中获得a标记22的偏移顶部,并且在滚动时保持相同,

但是当我在滚动时使用jquery 3.1.1偏移更改时。

使用jquery 2.1.1

进行演示1



console.log($('a').offset().top);
$(window).scroll(function() {
  console.log($('a').offset().top);
})

body {
  height: 1200px;
}
a {
  font-size: 0;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#">hidden anchor</a>
&#13;
&#13;
&#13;

使用jquery 3.1.1

进行演示2

&#13;
&#13;
console.log($('a').offset().top);
$(window).scroll(function() {
  console.log($('a').offset().top);
})
&#13;
body {
  height: 1200px;
}
a {
  font-size: 0;
  display: inline-block;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<a href="#">hidden anchor</a>
&#13;
&#13;
&#13;

为什么会这样。

2 个答案:

答案 0 :(得分:2)

jQuery 2具有正确的行为; offset()与文档相关,因此滚动位置不应更改它。

请注意这里强调的位:

  

使用.offset()方法时,jQuery集合中的第一项必须是具有DOM getBoundingClientRect()方法的DOM元素。 (jQuery 3.0支持的所有浏览器都有此API。)任何其他输入都可能导致jQuery抛出错误。 另请注意,该元素必须可见且当前位于文档中(即未断开连接)。 https://jquery.com/upgrade-guide/3.0/#offset

当元素可见时,你在jQuery 3中得到了正确的行为(offset()无论滚动位置如何都保持不变)但是当使用font-size:0隐藏元素时,offset()错误地返回一个视口相对值(据我所知,它通过隐藏元素的视口相对getBoundingClientRect()值。我不知道为什么会这样做,但数字匹配)。

console.log($('a.visible').offset().top);
console.log($('a.visible')[0].getBoundingClientRect();
console.log($('a.hidden').offset().top);
console.log($('a.hidden')[0].getBoundingClientRect();
$(window).scroll(function() {
   console.log($('a.visible').offset().top);
   console.log($('a.visible')[0].getBoundingClientRect();
   console.log($('a.hidden').offset().top);
   console.log($('a.hidden')[0].getBoundingClientRect();
})
body {
  height: 1200px;
}
a {
  display: inline-block;
}

a.hidden {
    font-size: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<a class="visible" href="#">Not-hidden anchor</a>
<a class="hidden" href="#">hidden anchor</a>

最好的解决方法似乎是不尝试测试隐藏元素的位置;使用一些带有真实文档位置的容器元素。

答案 1 :(得分:1)

正如许多人所指出的那样,这是由于offset使用隐藏元素的方式发生了变化。我已经挖掘了代码,并且遇到了负责该行为的代码片段:

rect = elem.getBoundingClientRect();

    // Make sure element is not hidden (display: none)
    if ( rect.width || rect.height ) { //this line is responsible
        doc = elem.ownerDocument;
        win = getWindow( doc );
        docElem = doc.documentElement;

        return {
            top: rect.top + win.pageYOffset - docElem.clientTop,
            left: rect.left + win.pageXOffset - docElem.clientLeft
        };
    }

    // Return zeros for disconnected and hidden elements (gh-2310)
    return rect;

相关的行是if (rect.width || rect.height),这意味着,如果元素没有高度或宽度,它会跳过该部分并返回相对位置。

但是,它似乎已经fixed in the current code,所以它应该再次适用于较新的版本。现在,jQuery不会检查getBoundingClientRect()的宽度或高度,而是检查getClientRects()的结果。

if ( !elem.getClientRects().length ) {
  return { top: 0, left: 0 };
}

当文本隐藏font-size:0时,getClientRects()返回一个包含一些值的数组,而真正隐藏的元素(display:none)的结果返回一个空数组,因此更新条件将适用于“软”(?) - 隐藏元素。

console.log(document.getElementById('hidden').getClientRects());

console.log(document.getElementById('removed').getClientRects());
#hidden{
  font-size:0;
 }
#removed{
   display:none;  
}
<div id="hidden">I'm hidden.</div>
<div id="removed">I'm display:none</div>