如何解决如何在滚动时替换粘性元素? 上下文问题代码
上下文
我正在制作一个博客网站,我希望有一个粘性元素,该元素会随着用户滚动而在每个新的一年和每个月更新。这样标题就会显示列出的博客文章的当前月份和年份。
在编码时,我尝试使用 HTML 实现效果,如果它不起作用,则使用 CSS,如果仍然不起作用,则使用 JS。我相信这是一种很好的做法,因为它使用内置功能并减少所需的计算资源,但如果您不同意此观点,请告诉我。
问题
理想情况下,元素的样式会在“卡住”时发生变化。为此,我查看了使用 IntersectionObserver
的 David Walsh's solution,但在添加多个元素时会出现故障。
我面临的主要问题是,当有多个条目时,脚本会在元素位于窗口底部边框时将其检测为“固定”。
代码
这是一个片段。我也做了一个jsfiddle with the same code。
//Essentially putting David Walsh's code in a loop
document.querySelectorAll(".myElement").forEach((i) => {
const observer = new IntersectionObserver(([i]) => i.target.classList.toggle("is-pinned",i.intersectionRatio < 1),{threshold: [1]});
observer.observe(i);
})
#parent {
height: 2000px;
}
.myElement {
position: sticky;
top: -1px;
}
/* styles for when the header is in sticky mode. The transition times accentuate the undesired effect */
.myElement.is-pinned {
color: red;
transition: color 0.3s,background-color 0.3s;
background-color: orange;
}
<div id="parent">
<!-- Adding more than one 'hello' element. The br's are here to add vertical space and be longer than the viewport height -->
<br><br><br><br>
<div class="myElement">Hello!</div>
<br><br><br><br>
<div class="myElement">Hello 2!</div>
<br><br><br><br>
<div class="myElement">Hello 3!</div>
<br><br><br><br>
<div class="myElement">Hello 4!</div>
<br><br><br><br>
<div class="myElement">Hello 5!</div>
<br><br><br><br>
<div class="myElement">Hello 6!</div>
<br><br><br><br>
<div class="myElement">Hello 7!</div>
<br><br><br><br>
<div class="myElement">Hello 8!</div>
</div>
解决方法
首先,您只需要一个 IntersectionObserver
。只要您需要相同的回调和选项(您在本例中就是这样做的),您就可以使用同一个观察者 observe()
多个元素。只有您的 observer.observe(i);
需要在循环内。
但是,如果您向上或向下跳转页面,则您的单个观察者可以一次被多个条目调用。所以你需要遍历所有观察到的条目。
更重要的是,intersectionRatio
并不关心元素在屏幕上的位置。元素在框的顶部和底部均超过 100% 可见性阈值。
你只关心盒子顶部的元素。 IntersectionObserverEntry
对象还有一个 boundingClientRect
属性,它告诉您元素现在的位置。您可以使用它来仅切换顶部的元素。
所以你最终是这样的:
const observer = new IntersectionObserver((entries) => {
for (let i of entries) {
i.target.classList.toggle(
"is-pinned",i.boundingClientRect.y < 0);
}
},{threshold: [1]});
document.querySelectorAll(".myElement").forEach(i => observer.observe(i));
然而,这仍然会给您带来问题。在您的示例中,您滚动的框足够长,如果您从顶部直接跳到底部,则有元素从“框下方 0% 可见”到“框顶部 99% 可见”。这不会超过 100% 阈值,因此 IntersectionObserver 回调永远不会为这些元素触发!这意味着他们没有获得 is-pinned
课程。
您可以简单地向同一个观察者添加另一个阈值 0% 来捕捉这些变化:
const observer = new IntersectionObserver((entries) => {
for (let i of entries) {
i.target.classList.toggle(
"is-pinned",{threshold: [0,1]});
document.querySelectorAll(".myElement").forEach(i => observer.observe(i));
现在,从可见到粘性(或反之亦然)的元素和从不可见到粘性(反之亦然)的元素都切换了它们的类。
,您在 JS 的最后一行中犯了一个错误。改为:
document.querySelectorAll(".myElement").forEach((i) => {
const observer = new IntersectionObserver(
([i]) => i.target.classList.toggle("is-pinned",i.intersectionRatio < 1),{
threshold: [1]
});
observer.observe(document.querySelector(".myElement")); // Use the element instead!
})
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。