覆蓋瀏覽器默認滾動行為,每次滾輪滾動固定距離(如 700px),實現類似「親寶寶官網」的全屏翻頁效果。
let isScrolling = false;
const SCROLL_DISTANCE = 700; // 固定滾動距離
const SCROLL_DURATION = 800; // 動畫時長 ms
window.addEventListener('wheel', (e) => {
if (isScrolling) return; // 防止動畫期間重複觸發
e.preventDefault(); // 禁用默認滾動
const direction = e.deltaY > 0 ? 1 : -1; // 向下/向上
const targetY = window.scrollY + direction * SCROLL_DISTANCE;
// 邊界檢查
const maxScroll = document.documentElement.scrollHeight - window.innerHeight;
const clampedY = Math.max(0, Math.min(targetY, maxScroll));
smoothScrollTo(clampedY);
}, { passive: false }); // 必須 passive: false 才能 preventDefault
function smoothScrollTo(targetY) {
isScrolling = true;
const startY = window.scrollY;
const startTime = performance.now();
function animate(currentTime) {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / SCROLL_DURATION, 1);
// 緩動函數
const ease = 1 - Math.pow(1 - progress, 3); // cubic ease-out
window.scrollTo(0, startY + (targetY - startY) * ease);
if (progress < 1) {
requestAnimationFrame(animate);
} else {
isScrolling = false;
}
}
requestAnimationFrame(animate);
}
更適合「全屏輪播」場景,確保每次滾動精準對齊區塊:
const sections = document.querySelectorAll('.full-screen-section');
let currentIndex = 0;
let isAnimating = false;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
currentIndex = Array.from(sections).indexOf(entry.target);
}
});
}, { threshold: 0.5 });
sections.forEach(sec => observer.observe(sec));
window.addEventListener('wheel', (e) => {
if (isAnimating) return;
e.preventDefault();
const dir = e.deltaY > 0 ? 1 : -1;
const nextIndex = Math.max(0, Math.min(currentIndex + dir, sections.length - 1));
if (nextIndex !== currentIndex) {
scrollToSection(nextIndex);
}
}, { passive: false });
function scrollToSection(index) {
isAnimating = true;
sections[index].scrollIntoView({ behavior: 'smooth' });
// 監聽滾動結束
const onScrollEnd = () => {
isAnimating = false;
window.removeEventListener('scroll', onScrollEnd);
};
window.addEventListener('scroll', onScrollEnd, { once: true });
}
| 問題 | 解決方案 |
|---|---|
| Mac 觸控板連續滾動觸發多次 | 節流:setTimeout 或 requestAnimationFrame 鎖定 isScrolling |
| 移動端無滾輪事件 | 補充 touchstart/touchmove/touchend 手勢判斷上下滑動 |
| 鍵盤方向鍵/空格鍵導航 | 監聽 keydown,映射 ArrowDown/Up、Space/Shift+Space 觸發同樣邏輯 |
| 無障礙訪問 | 提供「禁用自定義滾動」開關,保留原生滾動條供輔助技術使用 |
will-change: transform 提示瀏覽器優化wheel 監聽器中執行佈局觸發操作(offsetHeight 等)