Tạo hiệu ứng, infinite scroll, lazy load hình ảnh khi scroll chuột

Một số task thường gặp trên web liên quan đến scroll:

  • Các hiệu ứng hoạt hình khi đối tượng xuất hiện trên màn hình (in view)
  • Tải thêm tin tức, nội dung khi kéo chuột đến cuối trang (infinite scroll)
  • Load hình khi user scroll tới (lazy load images)
  • Đổi hash khi user scroll qua các section trên trang
  • Active menu item khi user scroll tới section tương ứng

Theo cách làm cũ, chúng ta sẽ listen sự kiện scroll, kiểm tra các phần tử theo từng lần scroll đó để thực hiện các hành động cần thiết, điều này có thể ảnh hưởng rất nhiều đến hiệu năng, chưa kể bạn cần phải tự xử lý các thứ như throttling, caching,… nói chung là đau đầu.

May thay, các trình duyệt đã hỗ trợ một API mới giúp bạn làm điều này dễ dàng hơn, xin giới thiệu: IntersectionObserver class, với vài dòng code đơn giản, không cần gắn thêm bất kỳ thư viện nào vào, bạn có thể thực hiện số tác vụ trên với hiệu năng tốt hơn scroll listening rất nhiều. Bạn có thể tìm đọc các bài so sánh hiệu năng giữa scroll listening & IntersectionObserver.

Nào, bắt đầu thôi.

Nếu bạn là một nguuời thích học trực quan, hãy xem video này

Đầu tiên, khởi tạo một đối tượng IntersectionObserver

const observer = new IntersectionObserver(entries => {
  console.log(entries)
})

Như bạn thấy, Class IntersectionObserver nhận vào một callback, tại đây, bạn nhận các đối tượng (trong biến entries) và kiểm tra xem nó có đang “in view” hay không. Ví dụ:

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

Ở đây, chúng ta chạy loop qua tất cả đối tượng nhận được và toggle class active nếu đối tượng đang xuất hiện trong viewport (entry.isIntersecting).

Giờ chúng ta hãy cho nó vào một ví dụ thực tế, ở đây, mình muốn khi scroll chuột đến đâu thì nội dung xuất hiện đến đó.

Chuẩn bị một file HTML cơ bản với một số “Card”

Các card này trong trạng thái bình thường sẽ ẩn (opacity = 0) và lệch về bên trái -50px, khi có thêm class active Card sẽ hiện lên từ từ (opacity = 1) và chuyển động về bên phải 50px (translateX từ -50px -> 0).

Giờ nhiệm vụ của chúng ta là thêm class active vào các card đã lọt vào view port.

Viết file app.js

Trong file này, chúng ta làm các việc sau:

  1. Query tất cả “Card” đang có trong trang
  2. Tạo một đối tượng observer, trong đó truyền vào các đối tượng, chạy qua tất cả các đối tượng đó và thêm / bỏ class active tuỳ theo nó có đang được cho là intersecting hay không
  3. Loop qua các Card, và cho observerobserve” từng card.

Hiển nhiên, bước cuối, bạn cần link file app.js vào file index.html để hoàn tất.

Xem demo tại đây.