Người Quan Sát Giao Lộ | Tạo cuộn vô hạn trong ứng dụng web của bạn

Nov 25 2022
Nếu bạn không phải là người thích hang động hoặc bạn không ghét Jeff Bezos (không quan trọng nếu bạn ghét), bạn hẳn đã mua sắm trực tuyến. Khi bạn tìm kiếm một mặt hàng trên các cửa hàng trực tuyến này, bạn sẽ thấy một danh sách kết quả.
Ảnh của SpaceX trên Bapt

Nếu bạn không phải là người thích hang động hoặc bạn không ghét Jeff Bezos (không quan trọng nếu bạn ghét), bạn hẳn đã mua sắm trực tuyến. Khi bạn tìm kiếm một mặt hàng trên các cửa hàng trực tuyến này, bạn sẽ thấy một danh sách kết quả. Nếu bạn không kỳ quặc như tôi và không tìm kiếm “ răng hổ ngâm trong máu người” quá cụ thể, thì có khả năng truy vấn tìm kiếm của bạn sẽ nhận được hàng nghìn sản phẩm. Bạn có nghĩ rằng trình duyệt của mình tải tất cả hơn 1000 mục này không? Không , đó sẽ là quá nhiều dữ liệu để trình duyệt xử lý và tính toán giao diện người dùng. Tuy nhiên, bạn vẫn tiếp tục nhận được vật phẩm khi bạn tiếp tục đạt đến cuối kết quả của mình. Điều này được gọi là cuộn vô hạn .

Dưới đây là một ví dụ về cuộn vô hạn trên trang chủ YouTube.

Gif giải thích cuộn vô hạn

Có một số kỹ thuật để đạt được điều này bằng cách sử dụng JavaScript, nhưng kỹ thuật hiệu quả nhất là sử dụng api web ngọt ngào có tên là IntersectionObserver. Hãy xem cách sử dụng API này để triển khai danh sách có thể cuộn vô hạn nhỏ của riêng chúng ta.

Khái niệm này là, quan sát một phần tử html mỗi khi nó xuất hiện trong chế độ xem và sau đó kích hoạt một cuộc gọi lại. Đây là cách tạo trình quan sát này.

Hãy tạo một tệp html trông như thế này.

<!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>

Trước tiên, hãy lấy tất cả các thẻ sản phẩm theo tên lớp của chúng

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);
})

Một tham số khác trong hàm tạo là một đối tượng. Những đối tượng này biểu thị các tùy chọn cho người quan sát cụ thể này. Trong trường hợp này, chúng tôi chỉ có ngưỡng. ngưỡng ở đây là một số có thể nhận bất kỳ giá trị nào từ 0 đến 1. Điều này biểu thị tỷ lệ phần trăm của mục chúng tôi đang quan sát sẽ hiển thị trong chế độ xem để mục đó được coi là giao nhau. chúng tôi đã cho nó một giá trị là 0,95, điều đó có nghĩa là khi 95% của bất kỳ thẻ sản phẩm nào xuất hiện trong chế độ xem, thì thẻ đó sẽ được coi là giao nhau với chế độ xem.

Hãy quay lại tệp index.html của chúng tôi . Chúng tôi cũng có một lớp kiểu khác có thể nhìn thấy được xác định trong thẻ kiểu. Kiểu này, khi được áp dụng cho thẻ sản phẩm của chúng tôi, sẽ làm cho thẻ hiển thị lại với một hoạt ảnh nhỏ ( thuộc tính chuyển đổi ).

Hãy thực hiện các thay đổi đối với trình quan sát sao cho tất cả các thẻ sản phẩm chiếm ít nhất 95% trong chế độ xem sẽ hiển thị và phần còn lại sẽ bị ẩn.

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);
});

Có một nắm bắt mặc dù. Khi chúng tôi cuộn lên, vì chúng tôi có logic để chuyển đổi lớp hiển thị khi mục giao nhau, nó cũng loại bỏ lớp này khi không. Vì vậy, khi cuộn lên, chúng tôi thấy các thẻ của mình biến mất ở trên cùng. Để khắc phục điều này, chúng tôi sẽ ngừng quan sát các thẻ đã giao nhau.

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);
});

Đầu tiên, chúng ta sẽ tạo một người quan sát khác sẽ chỉ quan sát lá bài cuối cùng.

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);
    }
}

Đây là cách nó trông bây giờ!

Cuộn giấy vô hạn hoàn hảo!

Giờ đây, trong các ứng dụng trong thế giới thực, thay vì tải thêm thẻ, chúng tôi sẽ tìm nạp dữ liệu mới bằng API.

Hãy cho tôi biết cách bạn có thể sử dụng API này một cách sáng tạo trong các ứng dụng của mình.