ผู้สังเกตการณ์ทางแยก | การสร้างการเลื่อนที่ไม่มีที่สิ้นสุดในเว็บแอปพลิเคชันของคุณ

Nov 25 2022
หากคุณไม่ใช่คนติดถ้ำหรือไม่ได้เกลียด Jeff Bezos (แม้ว่าคุณจะเกลียดก็ตาม) คุณต้องเคยซื้อของออนไลน์มาก่อน เมื่อคุณค้นหาสินค้าในร้านค้าออนไลน์เหล่านี้ คุณจะเห็นรายการผลลัพธ์
ภาพถ่ายโดย SpaceX บน Unsplash

หากคุณไม่ใช่คนติดถ้ำหรือไม่ได้เกลียด Jeff Bezos (แม้ว่าคุณจะเกลียดก็ตาม) คุณต้องเคยซื้อของออนไลน์มาก่อน เมื่อคุณค้นหาสินค้าในร้านค้าออนไลน์เหล่านี้ คุณจะเห็นรายการผลลัพธ์ หากคุณไม่แปลกเหมือนฉันและไม่ได้มองหา “ ฟันเสือโชกเลือดมนุษย์”ซึ่งเฉพาะเจาะจงเกินไป มีโอกาสที่คำค้นหาของคุณจะได้รับสินค้าหลายพันรายการ คุณคิดว่าเบราว์เซอร์ของคุณโหลดรายการทั้งหมดมากกว่า 1,000 รายการเหล่านี้หรือไม่ ไม่นั่นอาจเป็นข้อมูลที่มากเกินไปสำหรับเบราว์เซอร์ที่จะจัดการและคำนวณอินเทอร์เฟซผู้ใช้ ถึงกระนั้นคุณยังคงได้รับไอเท็มต่อไปเมื่อถึงจุดสิ้นสุดของผลลัพธ์ สิ่งนี้เรียกว่าการเลื่อนที่ ไม่มีที่สิ้นสุด

นี่คือตัวอย่างการเลื่อนแบบไม่จำกัดบนหน้าแรกของ YouTube

Gif อธิบายการเลื่อนที่ไม่มีที่สิ้นสุด

มีหลายเทคนิคในการบรรลุสิ่งนี้โดยใช้ JavaScript แต่วิธีที่มีประสิทธิภาพมากที่สุดคือการใช้ Sweet Web API ที่เรียกว่าIntersectionObserver มาดูวิธีใช้ API นี้เพื่อปรับใช้รายการเลื่อนแบบไม่จำกัดขนาดเล็กของเราเอง

แนวคิดคือการสังเกตองค์ประกอบ html ทุกครั้งที่เข้ามาในวิวพอร์ต จากนั้นเรียกใช้การเรียกกลับ นี่คือวิธีสร้างผู้สังเกตการณ์นี้

มาสร้างไฟล์ html ซึ่งมีลักษณะดังนี้

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinte Scroll</title>
</head>
<style>
    .product {
        padding: 20px;
        border: 1px solid black;
        margin-bottom: 20px;
        opacity: 0;
        margin-left: 100px;
        transition: all 300ms;
    }
    .visible {
        opacity: 1;
        margin-left: 0px;
    }
</style>
<body>
    <div id="container">
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
        <div class="product">Product</div>
    </div>

    <script src="./index.js"></script>
</body>
</html>

ก่อนอื่น มารับการ์ดผลิตภัณฑ์ทั้งหมดตามชื่อคลาส

const cards = document.querySelectorAll('.product');

const productCards= document.querySelectorAll('.product');

const observer = new IntersectionObserver((entries) => {
    // Todo
}, {
    threshold: 0.95,
});

productCards.forEach((card) => {
  observer.observe(card);
})

พารามิเตอร์อื่นในตัวสร้างคือวัตถุ วัตถุเหล่านี้หมายถึงตัวเลือกสำหรับผู้สังเกตการณ์รายนี้ ในกรณีนี้ เรามีเกณฑ์เท่านั้น เกณฑ์ในที่นี้คือตัวเลขที่สามารถรับค่าใดก็ได้ตั้งแต่ 0 ถึง 1ซึ่งหมายถึงเปอร์เซ็นต์ของรายการที่เรากำลังสังเกตซึ่งควรมองเห็นได้ในวิวพอร์ตเพื่อให้ถือว่าตัดกัน เราให้ค่าเป็น 0.95 ซึ่งหมายความว่าเมื่อ 95% ของการ์ดผลิตภัณฑ์ใด ๆ จะมาในวิวพอร์ต การ์ดนั้นจะถือว่าตัดกับวิวพอร์ต

กลับไปที่ไฟล์index.html ของเรา เรายังมีคลาสสไตล์อื่นที่มองเห็นได้ในแท็กสไตล์ สไตล์นี้เมื่อใช้กับการ์ดผลิตภัณฑ์ของเรา จะทำให้การ์ดมองเห็นได้อีกครั้งพร้อมภาพเคลื่อนไหวเล็กน้อย ( คุณสมบัติ การเปลี่ยนภาพ )

มาทำการเปลี่ยนแปลงกับผู้สังเกตการณ์ของเรา เพื่อที่การ์ดผลิตภัณฑ์ทั้งหมดที่มีอย่างน้อย 95% ในวิวพอร์ตจะมองเห็นได้ และส่วนที่เหลือจะถูกซ่อนไว้

const productCards = document.querySelectorAll('.product');

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        entry.target.classList.toggle('visible', entry.isIntersecting);
    })
}, {
    threshold: 0.95
});

productCards.forEach((card) => {
    observer.observe(card);
});

มีสิ่งหนึ่งที่จับได้ เมื่อเราเลื่อนขึ้น เนื่องจากเรามีตรรกะในการสลับคลาสที่มองเห็นได้เมื่อไอเท็มตัดกัน คลาสนี้จะลบคลาสนี้เมื่อไม่ใช่ด้วย เมื่อเราเลื่อนขึ้น เราจะเห็นการ์ดของเราหายไปจากด้านบน เพื่อแก้ไขปัญหานี้ เราจะเลิกสังเกตไพ่ที่ตัดกันไปแล้ว

const productCards = document.querySelectorAll('.product');

const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        entry.target.classList.toggle('visible', entry.isIntersecting);
        // unobserving entries which have already intersected
        if (entry.isIntersecting) observer.unobserve(entry.target);
    })
}, {
    threshold: 0.95
});

productCards.forEach((card) => {
    observer.observe(card);
});

ขั้นแรก เราจะสร้างผู้สังเกตการณ์อีกคนซึ่งจะสังเกตไพ่ใบสุดท้าย

const lastCardObserver = new IntersectionObserver((entries) => {
    const lastCard = entries[0];
    if (!lastCard.isIntersecting) return;
    loadMoreCards();
    lastCardObserver.unobserve(lastCard.target);
    lastCardObserver.observe(document.querySelector('.product:last-child'));
}, {
    threshold: 0.95
});

lastCardObserver.observe(document.querySelector('.product:last-child'));

function loadMoreCards() {
    const container = document.getElementById('container');
    for (let i = 0; i < 10; i++) {
        const element = document.createElement('div');
        element.classList.add('product');
        element.innerText = 'Product';
        observer.observe(element);
        container.appendChild(element);
    }
}

นี่คือลักษณะที่ปรากฏในขณะนี้!

สุดยอด Infinite Scroll !

ตอนนี้ในแอปพลิเคชันในโลกแห่งความเป็นจริง แทนที่จะต้องโหลดการ์ดเพิ่ม เราจะดึงข้อมูลใหม่โดยใช้ API

แจ้งให้เราทราบว่าคุณจะใช้ API นี้อย่างสร้างสรรค์ในแอปพลิเคชันของคุณได้อย่างไร