CSS position:sticky 元素吸顶时如何触发事件?

两个方法:

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 的缺点:

  • 兼容性较差,某些旧版本的浏览器不支持。
  • 无法实时获取元素的滚动位置和滚动方向。
  • 只能监听元素进入或离开视图,无法直接得知滚动的具体位置。

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值