那么,如何在触发事件时知道滚动方向?
在返回的对象中,我看到的最接近的可能性是与保存最后滚动位置的boundingClientRect
类型进行交互,但我不知道处理boundingClientRect
是否会最终导致性能问题。
是否可以使用交叉点事件来计算滚动方向(向上/向下)?
我添加了这个基本代码段,所以如果有人可以帮助我 我将非常感激。
以下是摘录:
var options = {
rootMargin: '0px',
threshold: 1.0
}
function callback(entries, observer) {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('entry', entry);
}
});
};
var elementToObserve = document.querySelector('#element');
var observer = new IntersectionObserver(callback, options);
observer.observe(elementToObserve);
#element {
margin: 1500px auto;
width: 150px;
height: 150px;
background: #ccc;
color: white;
font-family: sans-serif;
font-weight: 100;
font-size: 25px;
text-align: center;
line-height: 150px;
}
<div id="element">Observed</div>
我想知道这一点,所以我可以在固定标题菜单上应用它来显示/隐藏它
答案 0 :(得分:8)
我不知道处理boundingClientRect是否最终会遇到性能问题。
MDN指出IntersectionObserver
不在主线程上运行:
这样,站点不再需要在主线程上执行任何操作来监视这种元素交集,并且浏览器可以自由地优化交集的管理。
MDN, "Intersection Observer API"
我们可以通过保存IntersectionObserverEntry.boundingClientRect.y
的值并将其与先前的值进行比较来计算滚动方向。
运行以下代码段作为示例:
const state = document.querySelector('.observer__state')
const target = document.querySelector('.observer__target')
const thresholdArray = steps => Array(steps + 1)
.fill(0)
.map((_, index) => index / steps || 0)
let previousY = 0
let previousRatio = 0
const handleIntersect = entries => {
entries.forEach(entry => {
const currentY = entry.boundingClientRect.y
const currentRatio = entry.intersectionRatio
const isIntersecting = entry.isIntersecting
// Scrolling down/up
if (currentY < previousY) {
if (currentRatio > previousRatio && isIntersecting) {
state.textContent ="Scrolling down enter"
} else {
state.textContent ="Scrolling down leave"
}
} else if (currentY > previousY && isIntersecting) {
if (currentRatio < previousRatio) {
state.textContent ="Scrolling up leave"
} else {
state.textContent ="Scrolling up enter"
}
}
previousY = currentY
previousRatio = currentRatio
})
}
const observer = new IntersectionObserver(handleIntersect, {
threshold: thresholdArray(20),
})
observer.observe(target)
html,
body {
margin: 0;
}
.observer__target {
position: relative;
width: 100%;
height: 350px;
margin: 1500px 0;
background: rebeccapurple;
}
.observer__state {
position: fixed;
top: 1em;
left: 1em;
color: #111;
font: 400 1.125em/1.5 sans-serif;
background: #fff;
}
<div class="observer__target"></div>
<span class="observer__state"></span>
如果thresholdArray
辅助函数可能会使您感到困惑,则它会按照给定的步骤数量构建一个范围从0.0
到1.0
的数组。传递5
将返回[0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
。
答案 1 :(得分:6)
比较来自boundingClientRect
的{{1}}和rootBounds
,您可以轻松了解目标是在视口之上还是之下。
在entry
期间,检查isAbove / isBelow,最后将它存储到wasAbove / wasBelow。
下一次,如果目标进入视口(例如),您可以检查它是在上面还是下面。所以你知道它是来自顶部还是底部。
您可以尝试这样的事情:
callback()
希望这有帮助。
答案 2 :(得分:2)
:)
我认为单个阈值不可能实现这一点。您可以尝试注意intersectionRatio
,当容器离开视口时,大多数情况下1
低于1
(因为交叉点观察者触发异步)。如果浏览器足够迅速赶上,我很确定它也可能是threshold: [0.9, 1.0]
。 (我没试过这个:D)
但你可能做的是通过使用几个值来观察两个阈值。 :)
0.9
如果您首先获得{{1}}的事件,则表明容器已进入视口......
希望这会有所帮助。 :)
答案 3 :(得分:1)
我的要求是:
我需要查看IntersectionObserverEntry
提供的一些信息:
所以回调最终看起来像:
intersectionObserver = new IntersectionObserver(function(entries) {
const entry = entries[0]; // observe one element
const currentRatio = intersectionRatio;
const newRatio = entry.intersectionRatio;
const boundingClientRect = entry.boundingClientRect;
const scrollingDown = currentRatio !== undefined &&
newRatio < currentRatio &&
boundingClientRect.bottom < boundingClientRect.height;
intersectionRatio = newRatio;
if (scrollingDown) {
// it's scrolling down and observed image started to hide.
// so do something...
}
console.log(entry);
}, { threshold: [0, 0.25, 0.5, 0.75, 1] });
有关完整代码,请参阅my post。
答案 4 :(得分:0)
此解决方案不使用任何外部状态,因此比跟踪其他变量的解决方案更简单:
const observer = new IntersectionObserver(
([entry]) => {
if (entry.boundingClientRect.top < 0) {
if (entry.isIntersecting) {
// entered viewport at the top edge, hence scroll direction is up
} else {
// left viewport at the top edge, hence scroll direction is down
}
}
},
{
root: rootElement,
},
);