TABLE OF CONTENTS

Hi 🤓 Cảm ơn bạn đã ghé thăm blog này, nếu những bài viết trên blog giúp ích cho bạn. Bạn có thể giúp blog hiển thị quảng cáo bằng cách tạm ngừng ad blocker 😫 và để giúp blog duy trì hoạt động nếu bạn muốn.
Cảm ơn bạn!

Hello các bạn, lại là mình đây 😄. Hôm nay chúng ta sẽ cùng làm Infinite Scroll nhé. Để hiểu Infinite Scroll là gì thì đó là một hiệu ứng load dữ liệu khi chúng ta scroll chuột, dữ liệu sẽ được tải về (sử dụng AJAX) khi chúng ta scroll tới vị trí thích hợp 😁😁. Cùng tham khảo cách làm của mình để hiểu rõ hơn nhé !

DEMO

Chúng ta sẽ coi demo để xem nó hoạt động ra sao:

Thực hành

Đầu tiên mình sẽ tạo HTML:

<div class="wrapper">
  <h1>🔥 Infinite Scroll Blog 🌈</h1>

  <div class="container"></div>

  <div class="loading">
    <div class="circle"></div>
    <div class="circle"></div>
    <div class="circle"></div>
    <div class="circle"></div>
  </div>
</div>

Các post của blog mình sẽ thêm vào div container và tạo một loading, Khi load post thì loading sẽ hiện lên.

Cùng style một chút cho loading nhé:

.loading {
    opacity: 0;
    visibility: hidden;
    display: flex;
    position: fixed;
    bottom: 25px;
    transition: all 0.3s linear;
}

.loading.show {
    visibility: visible;
    opacity: 1;
}

.circle {
    background-color: rgb(163, 162, 162);
    width: 13px;
    height: 13px;
    border-radius: 50%;
    margin: 0 5px;
    animation: loading 0.4s linear infinite;
}

.circle:nth-of-type(2) {
    animation-delay: 0.1s;
}

.circle:nth-of-type(3) {
    animation-delay: 0.2s;
}

@keyframes loading {
    0%,
    100% {
        transform: translateY(0);
    }

    50% {
        transform: translateY(-10px);
    }
}

Tiếp theo chúng ta sẽ tới JavaScript:

Mình sẽ viết dưới dạng class nhé 😄, đầu tiên chúng ta tạo một class tên là Posts và thêm constructor cho class:

class Posts {
    constructor() {
        this.container = document.querySelector('.container');
        this.loading = document.querySelector('.loading');

        this.limit = 8;
        this.page = 1;
    }
}

Mình thêm vào constructor: limit là số lượng post tối đa load về trong 1 lần fetch API, page là vị trí page hiện tại 😁.

Để fetch API thì mình sử dụng trang jsonplaceholder các bạn có thể tìm hiểu thêm về trang này.

Tiếp theo ta tạo method để fetch API là getPosts, mình sử dụng một async function để xử lí bất đồng bộ:

async getPosts() {
  const result = await fetch(
    `https://jsonplaceholder.typicode.com/posts?_limit=${this.limit}&_page=${this.page}`
  );
  const data = await result.json();

  return data;
}

Các bạn có thể tìm hiểu về async/await tại: async await trong JavaScript là gì? nó giúp ích gì cho chúng ta

Sau khi dữ liệu được trả về thì mình tạo thêm method để insert dữ liệu vào DOM:

// insert post to DOM
    async showPosts() {
        const posts = await this.getPosts();
        posts.forEach((post) => {
            this.container.insertAdjacentHTML(
                'beforeend',
                `<div class="post">
                    <div class="number">${post.id}</div>
                    <div class="info">
                        <h2 class="title">${post.title}</h2>
                        <p class="description">${post.body}</p>
                    </div>
                </div>`
            );
        });
    }

OK như vậy là xong phần fetch data, tiếp theo chúng ta sẽ xử lí infinite scroll nhé 🔥

mình tạo một method để xử lí loading

handleLoading() {
  this.loading.classList.add('show');
  this.page++;

  setTimeout(() => {
    this.loading.classList.remove('show');

    setTimeout(() => {
      this.showPosts();
    }, 100);
  }, 1200);
}

Mình sẽ tăng page lên 1 đơn vị khi method này được gọi, đồng thời setTimeout cho loading một khoảng thời gian để chúng ta có thể nhìn thấy loading chuyển động. Sau đó mình sẽ sử dụng method showPosts để thêm vào DOM.

Phần class Posts chúng ta đã xử lí xong, tiếp theo chúng ta cần add các sự kiện:

document.addEventListener('DOMContentLoaded', eventListeners);
function eventListeners() {
  ...
}

Trong eventListeners() mình tạo một object và sử dụng method showPosts để thêm post vào DOM.

    const posts = new Posts();
    posts.showPosts();

Tiếp theo ta sẽ add sự kiện scroll cho window:

function eventListeners() {
    const posts = new Posts();
    posts.showPosts();

    window.addEventListener('scroll', function () {
        // get height and scrollTop of html
        //in html, client Height => get height browser
        //in html, offset Height => get height of document
        const {
            scrollHeight,
            scrollTop,
            clientHeight,
        } = document.documentElement;
        if (clientHeight + scrollTop >= scrollHeight) {
            posts.handleLoading();
        }
    });
}

Mình đã tính toán khi ta scroll đến vị trí post cuối cùng, cũng chính là vị trí cuối trang. vị trí đó chính bằng clientHeight + scrollTop.

Điều kiện để fetchAPI là khi ta scroll mouse tới vị trí lớn hơn hoặc bằng chiều cao của toàn bộ phần tử trong HTML.

Các bạn có thể đọc bài viết về scrollHeight, offsetHeight, clientHeight để hiểu rõ hơn về chúng tại đây.

Đây là kết quả của chúng ta:

Kết

Như vậy là chúng ta đã hoàn thành xong Infinite Scroll cho blog rồi. Nếu có thắc mắc gì về bài viết các bạn có thể liên hệ mình nhé 😁.

Happy coding 🔥

Bài viết nên đọc:

  1. Scrolling Nav with Vanilla Javascript
  2. Làm Dropdown Menu dễ dàng bằng Javascript
  3. Hướng dẫn làm slide sử dụng javascript
Có thể bạn thích ⚡
homiedev
About Me

Hi, I'm @devnav. Một người thích chia sẻ kiến thức, đặc biệt là về Frontend 🚀. Trang web này được tạo ra nhằm giúp các bạn học Frontend hiệu quả hơn 🎉😄.

Chúc các bạn tìm được kiến thức hữu ích trong blog này 😁😁.