JavaScript 實現(xiàn)頁面滾動動畫
在做前端 UI 效果時,讓元素根據滾動位置實現(xiàn)動畫效果是一個非常流行的設計,通常我們會使用第三方插件或庫來實現(xiàn)。在本教程中,我將教大家使用純 JavaScript 和 CSS 來實現(xiàn)。
先預覽一下實現(xiàn)的效果:

我們使用 CSS 來實現(xiàn)動畫,用 JavaScript 來處理觸發(fā)所需的樣式。我們先來創(chuàng)建布局。
創(chuàng)建布局
我們先使用 HTML 創(chuàng)建頁面布局,然后為需要實現(xiàn)動畫的元素分配一個通用類名,后面的 JavaScript 通過此類名定位這些元素。這里我們給需要根據滾動實現(xiàn)動畫的元素指定為類名 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>
添加 CSS 樣式
先來一個簡單的淡入動畫效果:
.js-scroll {
opacity: 0;
transition: opacity 500ms;
}
.js-scroll.scrolled {
opacity: 1;
}
頁面上的所有 js-scroll 元素都會被隱藏,不透明度為 0。當滾動到該元素區(qū)域時,給它加上 .scrolled 類名讓它顯現(xiàn)出來。
用 JavaScript 操作元素
有了布局和樣式,現(xiàn)在我們需要編寫一個 JavaScript 函數(shù),當元素滾動到視圖中時,為它們分配類名。
我們來簡單分解一下邏輯:
- 獲取頁面上所有 js-scroll 元素
- 使這些元素默認淡出不可見
- 檢測元素是否在視窗內
- 如果元素在視窗內則分配 scrolled 類名
獲取目標元素
獲取頁面上所有 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 來獲取視窗的高度。

我們將使用上述邏輯創(chuàng)建一個 elementInView 函數(shù):
const elementInView = (el) => {
const elementTop = el.getBoundingClientRect().top
return (
elementTop <= (window.innerHeight || document.documentElement.clientHeight)
)
}
我們可以修改這個函數(shù)來檢測元素是否向頁面滾動了 x 個像素,或者檢測頁面滾動的百分比。
const elementInView = (el, scrollOffset = 0) => {
const elementTop = el.getBoundingClientRect().top
return (
elementTop <=
(window.innerHeight || document.documentElement.clientHeight) - scrollOffset
)
}
在這種情況下,如果元素已經按 scrollOffset 的數(shù)量滾動到頁面中,該函數(shù)返回 true。我們再稍作修改,把參數(shù) scrollOffset 變成百分比:
const elementInView = (el, percentageScroll = 100) => {
const elementTop = el.getBoundingClientRect().top
return (
elementTop <=
(window.innerHeight || document.documentElement.clientHeight) *
(percentageScroll / 100)
)
}
這部分可以根據自己的特定需求來定義邏輯。
注意:可以使用 Intersection Observer API[2] 來實現(xiàn)同樣的效果,但它不支持 IE。
給元素添加類名
現(xiàn)在我們已經能夠檢測到元素是否已經滾動到頁面中,我們需要定義一個函數(shù)來處理該元素的顯示--本例中我們通過分配 scrolled 類名來顯示該元素。
const displayScrollElement = (element) => {
element.classList.add('scrolled')
}
然后,再把我們前面的邏輯與 displayScrollElement 函數(shù)結合起來,并使用 forEach 方法在所有 js-scroll 元素上調用該函數(shù)。
const handleScrollAnimation = () => {
scrollElements.forEach((el) => {
if (elementInView(el, 100)) {
displayScrollElement(el)
}
})
}
另外,當元素不再在視圖中時,需要將其重置為默認狀態(tài),我們可以通過定義一個 hideScrollElement 來實現(xiàn):
const hideScrollElement = (element) => {
element.classList.remove("scrolled");
};
const handleScrollAnimation = () => {
scrollElements.forEach((el) => {
if (elementInView(el, 100)) {
displayScrollElement(el);
} else {
hideScrollElement(el);
}
}
最后,我們將把上面的方法傳遞到窗口的滾動事件監(jiān)聽中,這樣每當用戶滾動時它就會運行。
window.addEventListener('scroll', () => {
handleScrollAnimation()
})
我們已經實現(xiàn)了滾動動畫的所有功能。
完善示例
請大家回到文章開頭看看效果圖??吹?,這些元素以不同的動畫出現(xiàn)。這是通過給類名分配不同的 CSS 動畫來實現(xiàn)的。這個示例的 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 1s ease-in-out both;
}
.scrolled.fade-in-bottom {
animation: fade-in-bottom 1s ease-in-out both;
}
.scrolled.slide-left {
animation: slide-in-left 1s ease-in-out both;
}
.scrolled.slide-right {
animation: slide-in-right 1s 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 代碼,因為邏輯保持不變。這意味著我們可以在頁面添加任何數(shù)量的不同動畫,而無需編寫新的函數(shù)。
利用節(jié)流閥提高性能
每當我們在滾動監(jiān)聽器中綁定一個函數(shù)時,每次用戶滾動頁面,該函數(shù)都會被調用。滾動一個 500px 的頁面會導致一個函數(shù)被調用至少 50 次。如果我們試圖在頁面上包含很多元素,這會導致我們的頁面速度明顯變慢。
我們可以通過使用“節(jié)流函數(shù)(Throttle Function)”來減少函數(shù)的調用次數(shù)。節(jié)流函數(shù)是一個高階函數(shù),它在指定的時間間隔內只調用傳入的函數(shù)一次。
它對于滾動事件特別有用,因為我們不需要檢測用戶滾動的每個像素。例如,如果我們有一個定時器為 100ms 的節(jié)流函數(shù),那么用戶每滾動 100ms,該函數(shù)將只被調用一次。
節(jié)流函數(shù)在 JavaScript 中可以這樣實現(xiàn):
let throttleTimer = false
const throttle = (callback, time) => {
if (throttleTimer) return
// 這里標記一下,以使函數(shù)不會重復執(zhí)行
throttleTimer = true
setTimeout(() => {
// 到了指定的時間,調用傳入的回調函數(shù)
callback()
throttleTimer = false
}, time)
}
然后我們可以修改 window 對象上的 scroll 事件監(jiān)聽:
window.addEventListener('scroll', () => {
throttle(handleScrollAnimation, 250)
})
現(xiàn)在我們的 handleScrollAnimation 函數(shù)在用戶滾動時每隔 250ms 就會被調用一次:

以上就是JavaScript 實現(xiàn)頁面滾動動畫的詳細內容,更多關于JavaScript 頁面滾動的資料請關注腳本之家其它相關文章!
相關文章
js防抖函數(shù)和節(jié)流函數(shù)使用場景和實現(xiàn)區(qū)別示例分析
這篇文章主要介紹了js防抖函數(shù)和節(jié)流函數(shù)使用場景和實現(xiàn)區(qū)別,結合實例形式詳細分析了js防抖函數(shù)和節(jié)流函數(shù)基本功能、定義、用法區(qū)別及操作注意事項,需要的朋友可以參考下2020-04-04
javascript在IE下trim函數(shù)無法使用的解決方法
這篇文章主要介紹了javascript在IE下trim函數(shù)無法使用的解決方法,分別敘述了javascript以及jQuery下的解決方案,對于WEB前端javascript設計人員進行瀏覽器兼容性調試有不錯的借鑒價值,需要的朋友可以參考下2014-09-09
javascript與CSS復習(《精通javascript》)
js和css結合來產生醒目的交互效果,我們可以快速的訪問元素自身的樣式屬性2010-06-06
Bootstrap Tooltip顯示換行和左對齊的解決方案
小編在使用Bootstrap的Tooltip功能時遇到一些小問題,換行丟失,文字不是左對齊。下面小編給大家介紹下Bootstrap Tooltip顯示換行和左對齊的解決方案,感興趣的朋友一起看看吧2017-10-10

