如何延迟路口观察器 API
How to delay intersection observer API
情况
我在页面顶部有一个固定的导航栏。当您向下滚动页面的不同部分时,导航栏会动态更新(下划线和突出显示)。您还可以单击导航栏上的某个部分,它会向下滚动到该部分。
这是通过使用交集观察器 API 来检测它在哪个部分并使用 scrollIntoView 滚动到每个部分来完成的。
问题
假设您在第 1 部分,然后单击最后一个部分 5,它会将页面向下滚动到中间的所有其他部分。滚动速度很快,当它滚动时,路口观察器会检测到所有部分,因此导航会更新。当每个导航项目经过每个对应部分时,您最终会得到导航快速变化的效果。
目标
如果该部分仅在帧中一毫秒,您如何延迟路口观察器触发菜单更改?快速滚动时,导航栏应仅在滚动停止在某个部分后更新。
代码设置
const sectionItemOptions = {
threshold: 0.7,
};
const sectionItemObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// select navigation link corresponding to section
} else {
// deselect navigation link corresponding to section
}
});
}, sectionItemOptions);
// start observing all sections on page
sections.forEach((section) => {
sectionItemObserver.observe(section);
});
想法
我的第一个想法是设置一个 setTimeout,这样在超时完成之前导航不会改变,然后如果该部分在超时完成之前离开屏幕,则取消超时。但是由于超时在 forEach 循环中,所以这不起作用。
const sectionItemObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
let selectNavTimeout
if (entry.isIntersecting) {
// Set timeout when section is scrolled past
selectNavTimeout = setTimeout(() => {
// select navigation link corresponding to section
}, 1000)
} else {
// deselect navigation link corresponding to section
// cancel timeout when section has left screen
clearTimeout(selectNavTimeout)
}
});
}, sectionItemOptions);
任何其他想法将不胜感激!谢谢:)
经过多次集思广益,我想出了一个想法,它并没有完全回答延迟 Intersection Observer 的问题API,但它确实解决了导航栏闪烁的问题。
导航项的突出显示是通过在其上添加 "is-active" class 然后对其应用 CSS 来完成的。因为 "is-active" class 仅在导航项上出现一瞬间,您可以使用 CSS 关键帧来延迟 CSS 样式的应用。当延迟结束时,"is-active" class 不在导航项上,并且没有样式更改。
保持原始 JS 相同,这是 CSS 使用的
.is-active {
animation: navItemSelected;
animation-duration: 0.3s;
// delay longer than the time nav item is in frame
animation-delay: 0.1s;
// fill mode to hold animation at the end
animation-fill-mode: forwards;
}
@keyframes navItemSelected {
// default non-selected style of nav item
from {
font-style: normal;
opacity: 0.5;
}
// highlighted style of nav item
to {
font-style: italic;
opacity: 1;
}
}
我遇到了同样的问题。我最终使用 setTimeout
方法。您需要将超时与入口目标相关联,前提是每个入口目标都有一些唯一的 ID。例如,假设我们与 id
属性:
相交的节点
let timeouts = {};
const observer = new IntersectionObserver((entries, ob) => {
for (const e of entries) {
if (e.isIntersecting) {
timeouts[e.target.id] = setTimeout(() => {
ob.unobserve(e.target)
// handling
}, 1000) // delay for 1 second
} else {
clearTimeout(timeouts[e.target.id])
}
}
}, options)
运行 进入同一期。根据这篇文章:https://web.dev/intersectionobserver-v2/,观察者 v2 允许您在观察者选项中设置延迟。在我的导航菜单情况下,延迟就像一个魅力:
const observer = new IntersectionObserver((changes) => {
for (const change of changes) {
// ⚠️ Feature detection
if (typeof change.isVisible === 'undefined') {
// The browser doesn't support Intersection Observer v2, falling back to v1 behavior.
change.isVisible = true;
}
if (change.isIntersecting && change.isVisible) {
visibleSince = change.time;
} else {
visibleSince = 0;
}
}
}, {
threshold: [1.0],
// Track the actual visibility of the element
trackVisibility: true,
// =====ANSWER=====: Set a minimum delay between notifications
delay: 100
}));
情况
我在页面顶部有一个固定的导航栏。当您向下滚动页面的不同部分时,导航栏会动态更新(下划线和突出显示)。您还可以单击导航栏上的某个部分,它会向下滚动到该部分。
这是通过使用交集观察器 API 来检测它在哪个部分并使用 scrollIntoView 滚动到每个部分来完成的。
问题
假设您在第 1 部分,然后单击最后一个部分 5,它会将页面向下滚动到中间的所有其他部分。滚动速度很快,当它滚动时,路口观察器会检测到所有部分,因此导航会更新。当每个导航项目经过每个对应部分时,您最终会得到导航快速变化的效果。
目标
如果该部分仅在帧中一毫秒,您如何延迟路口观察器触发菜单更改?快速滚动时,导航栏应仅在滚动停止在某个部分后更新。
代码设置
const sectionItemOptions = {
threshold: 0.7,
};
const sectionItemObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// select navigation link corresponding to section
} else {
// deselect navigation link corresponding to section
}
});
}, sectionItemOptions);
// start observing all sections on page
sections.forEach((section) => {
sectionItemObserver.observe(section);
});
想法
我的第一个想法是设置一个 setTimeout,这样在超时完成之前导航不会改变,然后如果该部分在超时完成之前离开屏幕,则取消超时。但是由于超时在 forEach 循环中,所以这不起作用。
const sectionItemObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
let selectNavTimeout
if (entry.isIntersecting) {
// Set timeout when section is scrolled past
selectNavTimeout = setTimeout(() => {
// select navigation link corresponding to section
}, 1000)
} else {
// deselect navigation link corresponding to section
// cancel timeout when section has left screen
clearTimeout(selectNavTimeout)
}
});
}, sectionItemOptions);
任何其他想法将不胜感激!谢谢:)
经过多次集思广益,我想出了一个想法,它并没有完全回答延迟 Intersection Observer 的问题API,但它确实解决了导航栏闪烁的问题。
导航项的突出显示是通过在其上添加 "is-active" class 然后对其应用 CSS 来完成的。因为 "is-active" class 仅在导航项上出现一瞬间,您可以使用 CSS 关键帧来延迟 CSS 样式的应用。当延迟结束时,"is-active" class 不在导航项上,并且没有样式更改。
保持原始 JS 相同,这是 CSS 使用的
.is-active {
animation: navItemSelected;
animation-duration: 0.3s;
// delay longer than the time nav item is in frame
animation-delay: 0.1s;
// fill mode to hold animation at the end
animation-fill-mode: forwards;
}
@keyframes navItemSelected {
// default non-selected style of nav item
from {
font-style: normal;
opacity: 0.5;
}
// highlighted style of nav item
to {
font-style: italic;
opacity: 1;
}
}
我遇到了同样的问题。我最终使用 setTimeout
方法。您需要将超时与入口目标相关联,前提是每个入口目标都有一些唯一的 ID。例如,假设我们与 id
属性:
let timeouts = {};
const observer = new IntersectionObserver((entries, ob) => {
for (const e of entries) {
if (e.isIntersecting) {
timeouts[e.target.id] = setTimeout(() => {
ob.unobserve(e.target)
// handling
}, 1000) // delay for 1 second
} else {
clearTimeout(timeouts[e.target.id])
}
}
}, options)
运行 进入同一期。根据这篇文章:https://web.dev/intersectionobserver-v2/,观察者 v2 允许您在观察者选项中设置延迟。在我的导航菜单情况下,延迟就像一个魅力:
const observer = new IntersectionObserver((changes) => {
for (const change of changes) {
// ⚠️ Feature detection
if (typeof change.isVisible === 'undefined') {
// The browser doesn't support Intersection Observer v2, falling back to v1 behavior.
change.isVisible = true;
}
if (change.isIntersecting && change.isVisible) {
visibleSince = change.time;
} else {
visibleSince = 0;
}
}
}, {
threshold: [1.0],
// Track the actual visibility of the element
trackVisibility: true,
// =====ANSWER=====: Set a minimum delay between notifications
delay: 100
}));