两个方法:
1、scroll
事件监听器
scroll 事件监听器是一种用于监听元素滚动的方法。当指定的元素滚动时,将触发该事件,并执行相应的处理函数。
使用 scroll 事件监听器可以监测各种元素的滚动情况,包括窗口、容器等。它可以实时获取元素的滚动位置和滚动方向,从而进行相应的处理操作。例如,可以通过监听滚动事件来实现懒加载、滚动加载数据、导航栏固定、滚动动画等效果。
2、IntersectionObserver
IntersectionObserver 是一种用于监测元素是否进入视图或者滚动的方法。它可以实现监听多个不同元素的进入和离开视图,并且可以设置阈值来准确控制何时触发事件。
使用 IntersectionObserver 可以避免传统的滚动监听方式中需要频繁获取滚动位置的问题,从而大幅度提高性能。它适用于需要在元素进入或离开视图时触发相应操作的场景,例如图片懒加载、滚动到某个元素时触发动画效果等。
scroll
事件监听器
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
header{
position: sticky;
top: 0;
/* not important styles */
background: salmon;
padding: 1em;
transition: .1s;
}
header.isSticky{
/* styles for when the header is in sticky mode */
font-size: .8em;
opacity: .5;
}
/* not important styles*/
body{ height: 200vh; font:20px Arial; }
section{
background: lightblue;
padding: 2em 1em;
}
</style>
</head>
<body>
<section>Space</section>
<header>Sticky Header</header>
<script>
// get the sticky element
// get the sticky element
const stickyElm = document.querySelector('header');
// get the first parent element which is scrollable
const stickyElmScrollableParent = getScrollParent(stickyElm);
// save the original offsetTop. when this changes, it means stickiness has begun.
stickyElm._originalOffsetTop = stickyElm.offsetTop;
// compare previous scrollTop to current one
const detectStickiness = (elm, cb) => () => cb & cb(elm.offsetTop != elm._originalOffsetTop)
// Act if sticky or not
const onSticky = isSticky => {
console.clear()
console.log(isSticky)
stickyElm.classList.toggle('isSticky', isSticky)
}
// bind a scroll event listener on the scrollable parent (whatever it is)
// in this exmaple I am throttling the "scroll" event for performance reasons.
// I also use functional composition to diffrentiate between the detection function and
// the function which acts uppon the detected information (stickiness)
const scrollCallback = throttle(detectStickiness(stickyElm, onSticky), 100)
stickyElmScrollableParent.addEventListener('scroll', scrollCallback)
// OPTIONAL CODE BELOW ///
// find-first-scrollable-parent
// Credit: https://stackoverflow.com/a/42543908/104380
function getScrollParent(element, includeHidden) {
var style = getComputedStyle(element),
excludeStaticParent = style.position === "absolute",
overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
if (style.position !== "fixed")
for (var parent = element; (parent = parent.parentElement); ){
style = getComputedStyle(parent);
if (excludeStaticParent && style.position === "static")
continue;
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX))
return parent;
}
return window
}
// Throttle
// Credit: https://jsfiddle.net/jonathansampson/m7G64
function throttle (callback, limit) {
var wait = false; // Initially, we're not waiting
return function () { // We return a throttled function
if (!wait) { // If we're not waiting
callback.call(); // Execute users function
wait = true; // Prevent future invocations
setTimeout(function () { // After a period of time
wait = false; // And allow future invocations
}, limit);
}
}
}
</script>
</body>
</html>
IntersectionObserver:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
body{ height: 200vh; font:20px Arial; }
section{
background: lightblue;
padding: 2em 1em;
}
header{
position: sticky;
top: -1px; /* ➜ the trick */
padding: 1em;
padding-top: calc(1em + 1px); /* ➜ compensate for the trick */
background: salmon;
transition: .1s;
}
/* styles for when the header is in sticky mode */
header.isSticky{
font-size: .8em;
opacity: .5;
}
</style>
</head>
<body>
<section>Space</section>
<header>Sticky Header</header>
<script>
// get the sticky element
const stickyElm = document.querySelector('header')
const observer = new IntersectionObserver(
([e]) => e.target.classList.toggle('isSticky', e.intersectionRatio < 1),
{threshold: [1]}
);
observer.observe(stickyElm)
</script>
</body>
</html>
scroll 事件监听器的优点:
- 监听任意元素的滚动,包括窗口、容器等。
- 可以实时获取元素的滚动位置和滚动方向。
- 可以在元素滚动过程中频繁触发事件,适用于需要实时响应滚动变化的场景。
- 兼容性较好,在各种浏览器环境下都可以使用。
scroll 事件监听器的缺点:
- 在滚动过程中频繁触发事件可能会造成性能问题,尤其是在复杂的页面中或监听多个元素的情况下。
- 监听整个页面滚动时,无法准确知道哪些元素进入或离开了视图。
IntersectionObserver 的优点:
- 支持观察多个不同的元素,可以同时监听多个元素的进入或离开视图。
- 可以设置阈值,准确控制何时触发事件。
- 使用回调函数,可以获取到元素进入或离开视图的具体信息。
- 对于复杂页面和大量元素的情况下,性能更优,因为它会在合适的时间触发事件。
IntersectionObserver 的缺点:
- 兼容性较差,某些旧版本的浏览器不支持。
- 无法实时获取元素的滚动位置和滚动方向。
- 只能监听元素进入或离开视图,无法直接得知滚动的具体位置。