[JavaScript 30]Day13-Slide In on Scroll
Published in
7 min readJun 5, 2022
今天要練習用純 JS,監聽 scroll 事件、計算高度,以及控制 CSS 樣式,做出類似 AOS 套件裡 fade-right
、fade-left
的動畫效果!
功能需求
- 當頁面滾動到超過圖片高度一半的位置,讓圖片由左或由右淡入顯示。
- 由頁面下方往回滾動至上方,也要有一樣的效果。
學習重點
- scroll 事件
- debounce 函式
- window.scrollY
- window.innerHeight (唯讀屬性)
- .offsetTop (唯讀屬性)
觀察範例檔案初始狀態
html :
範例中總共有 5 個圖片進入點,預設有 5 張圖片,都有 .slide-in
這個 class 名稱,搭配 .align-right
或 .align-left
例如 :
CSS :
與圖片淡入效果相關的 CSS 都預先寫好了
- 利用 float 讓圖片在文章中有文繞圖的效果
- 先預設 opacity 為 0,讓圖片先隱藏
- 加入 transition 設定,等等控制圖片出現才會有漸變效果
- 利用 transform 的 translateX 先將圖片往外位移, 以及 scale 設置,讓圖片小一些。
- 之後再利用 JS 判斷條件,加上
.active
這個 class,將 opacity 設回 1,translateX 將圖片拉回原位,scale 讓圖片變回原來大小,就可以達成我們要的淡入動畫效果。
JS :
已預先放了一段 debounce 程式碼,常用來防止事件頻繁被觸發。
在此範例中,可用來避免監聽 scroll event 時,在連續滾動的情況下,頻繁觸發事件,造成頁面效能負擔。
在第一行 wait=20 的參數位置,可以設定要延遲的毫秒數。
function debounce(func, wait = 20, immediate = true) { var timeout; return function() { var context = this, args = arguments; var later = function() { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); };}
(最後完成的完整 JS 程式碼,以及檔案下載、課程連結,將放在最下方)
解決思路
一、對 window 監聽 scroll event,觸發 checkSlide 事件
二、抓到判斷圖片滑入的基準點
三、計算出圖片最底部距離頁面最上方的高度值
四、判斷如果符合條件,就在圖片加上 .active
這個 class 以達到淡入動畫效果
一、對 window 監聽 scroll event,觸發 checkSlide 事件
- 為了防止事件被頻繁觸發,影響頁面效能,所以將事件利用 debounce 函式做處理。
二、抓到判斷圖片滑入的基準點
抓到當前視窗最底位置的高度值(依滾動的情況不同,此高度值會動態變化),減去圖片高度的一半
- 遍歷每一張圖片
- 當前視窗最底位置的高度值 = window.scrollY(已捲動的高度) + window.innerHeight(視窗高度)
- 圖片高度的一半 = sliderImage.height / 2
- slideInAt = 當前頁面最底位置的高度值 - 圖片高度的一半
三、計算出圖片最底部距離頁面最上方的高度值
- 利用
sliderImage.offsetTop
(圖片距離頁面最上方的高度),加上sliderImage.height
(圖片本身高度),來獲得圖片最底部距離頁面最上方的高度值 imageBottom
四、判斷如果符合條件,就在圖片加上 .active
這個 class 以達到淡入動畫效果
- 將判斷條件先存取至變數如 isHalfShown、isNotScrolledPast,可增加程式碼的可讀性,避免判斷式過長,難以閱讀。
- isHalfShown : 當剛剛設定的滑入基準點 slideInAt 高度值,大於圖片距離頁面最上方的高度距離(此時正是頁面滾動到超過圖片高度一半的位置)
- isNotScrolledPast : 圖片最底部還沒消失在視窗畫面
- 同時符合以上兩個條件,就在該圖片加上
.active
這個 class ,不符合則移除.active
。
到這邊就完成了今天要練習的圖片淡入效果~
完整 JS 程式碼
const sliderImages = document.querySelectorAll('.slide-in');function checkSlide(e) { sliderImages.forEach(sliderImage => { const slideInAt = (window.scrollY + window.innerHeight) - sliderImage.height / 2; const imageBottom = sliderImage.offsetTop + sliderImage.height; const isHalfShown = slideInAt > sliderImage.offsetTop; const isNotScrolledPast = window.scrollY < imageBottom; if(isHalfShown && isNotScrolledPast) { sliderImage.classList.add('active'); }else { sliderImage.classList.remove('active'); } })}window.addEventListener('scroll', debounce(checkSlide));