先预览一下实现的效果:
我们使用 CSS 来实现动画,用 JavaScript 来处理触发所需的样式。我们先来创建布局。
我们先使用 HTML 创建页面布局,然后为需要实现动画的元素分配一个通用类名,后面的 JavaScript 通过此类名定位这些元素。这里我们给需要根据滚动实现动画的元素指定为类名 js-scroll,HTML 代码如下:
?< section class = "scroll-container" > < div class = "scroll-element js-scroll" ></ div > < div class = "scroll-caption" >This animation fades in from the top.</ div > </ section > |
先来一个简单的淡入动画效果:
?.js- scroll { opacity: 0 ; transition: opacity 500 ms; } .js- scroll .scrolled { opacity: 1 ; } |
页面上的所有 js-scroll 元素都会被隐藏,不透明度为 0。当滚动到该元素区域时,给它加上 .scrolled 类名让它显现出来。
有了布局和样式,现在我们需要编写一个 JavaScript 函数,当元素滚动到视图中时,为它们分配类名。
我们来简单分解一下逻辑:
获取页面上所有 js-scroll 元素,使用 document.querySelectorAll() 即可:
? const scrollElements = document.querySelectorAll( '.js-scroll' ) |
遍历这些元素,使其全部淡出不可见:
?scrollElements.forEach((el) => { el.style.opacity = 0 }) |
我们可以通过判断元素距离页面顶部的间距是否小于页面可见部分的高度,来检测元素是否在用户视窗中。
在 JavaScript 中,我们使用 getBoundingClientRect().top
方法来获取元素与页面顶部的距离,使用 window.innerHeight
或 document.documentElement.clientHeight
来获取视窗的高度。
我们将使用上述逻辑创建一个 elementInView
函数:
const elementInView = (el) => { const elementTop = el.getBoundingClientRect().top return ( elementTop <= (window.innerHeight || document.documentElement.clientHeight) ) } |
我们可以修改这个函数来检测元素是否向页面滚动了 x 个像素,或者检测页面滚动的百分比。
?const elementInView = (el, scrollOffset = 0) => { const elementTop = el.getBoundingClientRect().top return ( elementTop <= (window.innerHeight || document.documentElement.clientHeight) - scrollOffset ) } |
在这种情况下,如果元素已经按 scrollOffset 的数量滚动到页面中,该函数返回 true。我们再稍作修改,把参数 scrollOffset 变成百分比:
?const elementInView = (el, percentageScroll = 100) => { const elementTop = el.getBoundingClientRect().top return ( elementTop <= (window.innerHeight || document.documentElement.clientHeight) * (percentageScroll / 100) ) } |
这部分可以根据自己的特定需求来定义逻辑。
注意:可以使用 Intersection Observer API[2] 来实现同样的效果,但它不支持 IE。
现在我们已经能够检测到元素是否已经滚动到页面中,我们需要定义一个函数来处理该元素的显示--本例中我们通过分配 scrolled 类名来显示该元素。
?const displayScrollElement = (element) => { element.classList.add( 'scrolled' ) } |
然后,再把我们前面的逻辑与 displayScrollElement 函数结合起来,并使用 forEach 方法在所有 js-scroll 元素上调用该函数。
?const handleScrollAnimation = () => { scrollElements.forEach((el) => { if (elementInView(el, 100)) { displayScrollElement(el) } }) } |
另外,当元素不再在视图中时,需要将其重置为默认状态,我们可以通过定义一个 hideScrollElement 来实现:
?const hideScrollElement = (element) => { element.classList.remove( "scrolled" ); }; const handleScrollAnimation = () => { scrollElements.forEach((el) => { if (elementInView(el, 100)) { displayScrollElement(el); } else { hideScrollElement(el); } } |
最后,我们将把上面的方法传递到窗口的滚动事件监听中,这样每当用户滚动时它就会运行。
?window.addEventListener( 'scroll' , () => { handleScrollAnimation() }) |
我们已经实现了滚动动画的所有功能。
请大家回到文章开头看看效果图。看到,这些元素以不同的动画出现。这是通过给类名分配不同的 CSS 动画来实现的。这个示例的 HTML 是这样的:
?< section class = "scroll-container" > < div class = "scroll-element js-scroll fade-in" ></ div > < div class = "scroll-caption" >淡入动效</ div > </ section > < section class = "scroll-container" > < div class = "scroll-element js-scroll fade-in-bottom" ></ div > < div class = "scroll-caption" >切入顶部动效</ div > </ section > < section class = "scroll-container" > < div class = "scroll-element js-scroll slide-left" ></ div > < div class = "scroll-caption" >从左边切入动效</ div > </ section > < section class = "scroll-container" > < div class = "scroll-element js-scroll slide-right" ></ div > < div class = "scroll-caption" >从右边切入动效</ div > </ section > |
这里我们给不同动效的元素分配了不同的 CSS 类名,下面是这些类对应的 CSS 代码:
?.scrolled.fade-in { animation: fade-in 1 s ease-in-out both ; } .scrolled.fade-in- bottom { animation: fade-in- bottom 1 s ease-in-out both ; } .scrolled.slide- left { animation: slide-in- left 1 s ease-in-out both ; } .scrolled.slide- right { animation: slide-in- right 1 s ease-in-out both ; } @keyframes slide-in- left { 0% { transform: translateX( -100px ); opacity: 0 ; } 100% { transform: translateX( 0 ); opacity: 1 ; } } @keyframes slide-in- right { 0% { transform: translateX( 100px ); opacity: 0 ; } 100% { transform: translateX( 0 ); opacity: 1 ; } } @keyframes fade-in- bottom { 0% { transform: translateY( 50px ); opacity: 0 ; } 100% { transform: translateY( 0 ); opacity: 1 ; } } @keyframes fade-in { 0% { opacity: 0 ; } 100% { opacity: 1 ; } } |
虽然加了不同动画元素,但我们不需要修改 JavaScript 代码,因为逻辑保持不变。这意味着我们可以在页面添加任何数量的不同动画,而无需编写新的函数。
每当我们在滚动监听器中绑定一个函数时,每次用户滚动页面,该函数都会被调用。滚动一个 500px 的页面会导致一个函数被调用至少 50 次。如果我们试图在页面上包含很多元素,这会导致我们的页面速度明显变慢。
我们可以通过使用“节流函数(Throttle Function)”来减少函数的调用次数。节流函数是一个高阶函数,它在指定的时间间隔内只调用传入的函数一次。
它对于滚动事件特别有用,因为我们不需要检测用户滚动的每个像素。例如,如果我们有一个定时器为 100ms 的节流函数,那么用户每滚动 100ms,该函数将只被调用一次。
节流函数在 JavaScript 中可以这样实现:
?let throttleTimer = false const throttle = (callback, time) => { if (throttleTimer) return // 这里标记一下,以使函数不会重复执行 throttleTimer = true setTimeout(() => { // 到了指定的时间,调用传入的回调函数 callback() throttleTimer = false }, time) } |
然后我们可以修改 window 对象上的 scroll 事件监听:
?window.addEventListener( 'scroll' , () => { throttle(handleScrollAnimation, 250) }) |
现在我们的 handleScrollAnimation 函数在用户滚动时每隔 250ms 就会被调用一次:
到此,关于“JS页面滚动动画效果的实现方法是什么”的学习就结束了,希望能够解决大家的疑惑,另外大家动手实践也很重要,对大家加深理解和学习很有帮助。如果想要学习更多的相关知识,欢迎关注群英网络,小编每天都会给大家分享实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
长按识别二维码并关注微信
更方便到期提醒、手机管理