Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

เหตุการณ์เลื่อน (Scroll Events) ใน JavaScript

Scroll Event เกิดขึ้นเมื่อผู้ใช้เลื่อน Scrollbar ของหน้าเว็บหรือองค์ประกอบที่มี Overflow เป็น Scroll/auto ใช้สำหรับ Infinite Scroll, Lazy Loading, Sticky Header, Parallax Effects ฯลฯ

ตัวอย่างพื้นฐาน: ตรวจจับ Scroll บน Window

<!DOCTYPE html>
<html lang="th">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroll Events</title>
    <style>
        body { 
            font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; 
            height: 150vh; /* สร้าง Scrollbar ให้ยาวพอ */
            padding: 20px;
        }
        .result { 
            position: fixed; 
            top: 20px; 
            right: 20px; 
            background: rgba(0,0,0,0.8); 
            color: white; 
            padding: 15px; 
            border-radius: 8px; 
            font-family: monospace;
            font-size: 14px;
            z-index: 1000;
        }
        .content { margin-top: 100px; }
        .section { height: 300px; border-bottom: 1px solid #eee; padding: 20px; }
    </style>
</head>
<body>
    <h1>Scroll Events ใน JavaScript</h1>
    <div class="result" id="scrollInfo">เลื่อนหน้าจอเพื่อดูค่า Scroll</div>
    <div class="content">
        <div class="section"><h2>Section 1</h2><p>เลื่อนลงไป...</p></div>
        <div class="section"><h2>Section 2</h2><p>ยังไม่ถึง...</p></div>
        <div class="section"><h2>Section 3</h2><p>เกือบจบ...</p></div>
        <div class="section"><h2>Section 4</h2><p>จบแล้ว!</p></div>
    </div>

    <script>
        const scrollInfo = document.getElementById("scrollInfo");
        
        // ใช้ Passive Listener เพื่อ Performance (ไม่เรียก preventDefault)
        window.addEventListener("scroll", () => {
            const scrollY = window.scrollY || window.pageYOffset;
            const scrollX = window.scrollX || window.pageXOffset;
            const docHeight = document.documentElement.scrollHeight - window.innerHeight;
            const scrollPercent = Math.round((scrollY / docHeight) * 100);
            
            scrollInfo.innerHTML = `
                Scroll Y: ${scrollY}px
Scroll X: ${scrollX}px
Progress: ${scrollPercent}%
Viewport: ${window.innerWidth}x${window.innerHeight} `; }, { passive: true }); // สำคัญ: เพื่อ Performance </script> </body> </html>

ผลลัพธ์

กล่องคงที่มุมขวาบน แสดงค่า Scroll Position, Progress % แทนที่จะแสดงแค่ "The scroll event has fired"

Performance Optimization (สำคัญมาก!)

1. ใช้ Passive Listeners

// ✅ ดี - Browser ไม่ต้องรอ preventDefault
window.addEventListener("scroll", handler, { passive: true });

// ❌ ไม่ดี - Browser ต้องรอดูว่าจะ preventDefault หรือไม่
window.addEventListener("scroll", handler);

2. Throttle / Debounce (จำกัดความถี่)

// Throttle: เรียกสูงสุด 1 ครั้งต่อ 100ms
function throttle(fn, limit) {
    let inThrottle;
    return function(...args) {
        if (!inThrottle) {
            fn.apply(this, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

window.addEventListener("scroll", throttle(() => {
    // Heavy work here
    updateStickyHeader();
    checkLazyLoad();
}, 100), { passive: true });

3. ใช้ Intersection Observer แทน (Modern, ประหยัดกว่า)

// แทนที่ Scroll Event สำหรับ Lazy Loading / Infinite Scroll
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            loadImage(entry.target);
            observer.unobserve(entry.target);
        }
    });
}, { rootMargin: "100px" }); // เริ่มโหลดก่อนเข้ามา 100px

document.querySelectorAll("img.lazy").forEach(img => observer.observe(img));

Scroll Event บน Element (ไม่ใช่ Window)

<div class="scroll-container" style="height: 300px; overflow-y: auto;">
    <div class="content">...เนื้อหายาว...</div>
</div>

<script>
    const container = document.querySelector(".scroll-container");
    
    container.addEventListener("scroll", (e) => {
        // e.target คือ container
        const { scrollTop, scrollHeight, clientHeight } = e.target;
        const isBottom = scrollTop + clientHeight >= scrollHeight - 10;
        
        if (isBottom) {
            loadMoreData();
        }
    }, { passive: true });
</script>

Scroll Event Properties

Propertyคำอธิบาย
window.scrollY / pageYOffsetตำแหน่ง Scroll แนวตั้ง (px)
window.scrollX / pageXOffsetตำแหน่ง Scroll แนวนอน (px)
element.scrollTopตำแหน่ง Scroll ใน Element
element.scrollLeftตำแหน่ง Scroll แนวนอนใน Element
element.scrollHeightความสูงรวมของเนื้อหา (รวมส่วนที่ซ่อน)
element.clientHeightความสูงส่วนที่มองเห็น (Viewport)

Scroll Restoration (History Navigation)


// ควบคุม Scroll Position เมื่อ Back/Forward
history.scrollRestoration = "manual"; // "auto" (default) หรือ "manual"

window.addEventListener("popstate", () => {
    // กู้ค่า Scroll Position ที่เก็บไว้
    window.scrollTo(0, savedScrollPosition);
});