IntersectionObserver sẽ xuất hiện

IntersectionObservers cho bạn biết thời điểm một phần tử được quan sát đi vào hoặc thoát khỏi khung nhìn của trình duyệt.

Hỗ trợ trình duyệt

  • Chrome: 51.
  • Edge: 15.
  • Firefox: 55.
  • Safari: 12.1.

Nguồn

Giả sử bạn muốn theo dõi thời điểm một phần tử trong DOM của bạn đi vào khung nhìn hiển thị. Bạn nên làm việc này để có thể tải từng phần hình ảnh kịp thời hoặc vì bạn cần biết liệu người dùng có thực sự đang xem một biểu ngữ quảng cáo nhất định hay không. Bạn có thể thực hiện việc đó bằng cách kết nối sự kiện cuộn hoặc bằng cách sử dụng bộ hẹn giờ định kỳ và gọi getBoundingClientRect() trên phần tử đó.

Tuy nhiên, phương pháp này khá chậm vì mỗi lệnh gọi đến getBoundingClientRect() buộc trình duyệt phải bố cục lại toàn bộ trang và sẽ khiến trang web của bạn bị giật đáng kể. Mọi việc sẽ trở nên gần như không thể khi bạn biết trang web của mình đang được tải bên trong một iframe và bạn muốn biết thời điểm người dùng có thể xem một phần tử. Mô hình nguồn gốc đơn và trình duyệt sẽ không cho phép bạn truy cập vào bất kỳ dữ liệu nào từ trang web chứa iframe. Đây là một vấn đề phổ biến đối với các quảng cáo, ví dụ như quảng cáo thường xuyên được tải bằng iframe.

IntersectionObserver được thiết kế để giúp kiểm thử khả năng hiển thị này hiệu quả hơn và đã có mặt trên tất cả trình duyệt hiện đại. IntersectionObserver cho bạn biết khi một phần tử được quan sát truy cập hoặc thoát khỏi khung nhìn của trình duyệt.

Chế độ hiển thị của iframe

Cách tạo IntersectionObserver

API này khá nhỏ và tốt nhất nên được mô tả bằng ví dụ:

const io = new IntersectionObserver(entries => {
  console.log(entries);
}, {
  /* Using default options. Details below */
});

// Start observing an element
io.observe(element);

// Stop observing an element
// io.unobserve(element);

// Disable entire IntersectionObserver
// io.disconnect();

Khi sử dụng các tuỳ chọn mặc định cho IntersectionObserver, lệnh gọi lại sẽ được gọi cả khi phần tử xuất hiện một phần trong khung nhìn và khi phần tử đó rời khỏi khung nhìn hoàn toàn.

Nếu cần quan sát nhiều phần tử, bạn có thể và nên quan sát nhiều phần tử bằng cách sử dụng cùng một thực thể IntersectionObserver bằng cách gọi observe() nhiều lần.

Tham số entries được truyền đến lệnh gọi lại. Đây là một mảng gồm các đối tượng IntersectionObserverEntry. Mỗi đối tượng như vậy chứa dữ liệu giao nhau đã cập nhật cho một trong các phần tử được quan sát.

🔽[IntersectionObserverEntry]
    time: 3893.92
    🔽rootBounds: ClientRect
        bottom: 920
        height: 1024
        left: 0
        right: 1024
        top: 0
        width: 920
    🔽boundingClientRect: ClientRect
    // ...
    🔽intersectionRect: ClientRect
    // ...
    intersectionRatio: 0.54
    🔽target: div#observee
    // ...

rootBounds là kết quả của việc gọi getBoundingClientRect() trên phần tử gốc, là khung nhìn theo mặc định. boundingClientRect là kết quả của getBoundingClientRect() được gọi trên phần tử được quan sát. intersectionRect là giao điểm của hai hình chữ nhật này và cho bạn biết phần nào của phần tử được quan sát là hiển thị. intersectionRatio có liên quan chặt chẽ và cho bạn biết mức độ hiển thị của phần tử. Giờ đây, bạn có thể tuỳ ý sử dụng thông tin này để có thể triển khai các tính năng như tải tài sản ngay lập tức trước khi chúng xuất hiện trên màn hình. Hiệu quả.

Tỷ lệ giao nhau.

IntersectionObserver phân phối dữ liệu không đồng bộ và mã gọi lại của bạn sẽ chạy trong luồng chính. Ngoài ra, thông số kỹ thuật thực sự còn cho biết rằng các hoạt động triển khai IntersectionObserver nên sử dụng requestIdleCallback(). Tức là lệnh gọi đến lệnh gọi lại mà bạn đã cung cấp có mức độ ưu tiên thấp và sẽ được trình duyệt thực hiện trong thời gian không hoạt động. Đây là một quyết định thiết kế có chủ ý.

Cuộn div

Tôi không thích cuộn bên trong một phần tử, nhưng tôi không phải là người đánh giá và IntersectionObserver cũng vậy. Đối tượng options sử dụng tuỳ chọn root cho phép bạn xác định một đối tượng thay thế cho khung nhìn làm gốc. Điều quan trọng cần lưu ý là root cần phải là phần tử cấp trên của tất cả các phần tử được quan sát.

Giao nhau tất cả mọi thứ!

Không đâu! Nhà phát triển xấu! Bạn chưa lưu tâm đến việc sử dụng chu kỳ CPU của người dùng. Hãy xem xét ví dụ về trình cuộn vô hạn: Trong trường hợp đó, bạn nên thêm sentinels vào DOM và quan sát (và tái chế!) chúng. Bạn nên thêm một sentinel gần mục cuối cùng trong thanh cuộn vô hạn. Khi người gửi đó xuất hiện, bạn có thể sử dụng lệnh gọi lại để tải dữ liệu, tạo các mục tiếp theo, đính kèm chúng vào DOM và đặt lại vị trí người gửi cho phù hợp. Nếu bạn tái chế đúng cách trình cảnh báo, bạn không cần gọi thêm observe(). IntersectionObserver tiếp tục hoạt động.

Công cụ cuộn vô hạn

Vui lòng cập nhật thêm

Như đã đề cập trước đó, lệnh gọi lại sẽ được kích hoạt một lần khi phần tử được quan sát xuất hiện một phần trong khung hiển thị và một lần khác khi phần tử đó đã rời khỏi khung nhìn. Bằng cách này, IntersectionObserver sẽ trả lời câu hỏi "Thành phần X có trong khung hiển thị không?". Tuy nhiên, trong một số trường hợp sử dụng, điều đó có thể chưa đủ.

Đó là lúc tuỳ chọn threshold phát huy tác dụng. Phương thức này cho phép bạn xác định một mảng các ngưỡng intersectionRatio. Lệnh gọi lại sẽ được gọi mỗi khi intersectionRatio vượt qua một trong các giá trị này. Giá trị mặc định của threshold[0], giải thích cho hành vi mặc định. Nếu thay đổi threshold thành [0, 0.25, 0.5, 0.75, 1], chúng ta sẽ nhận được thông báo mỗi khi một phần tư phần tử hiển thị thêm:

Ảnh động theo ngưỡng.

Bạn có lựa chọn nào khác không?

Hiện tại, chỉ có một tuỳ chọn bổ sung ngoài những tuỳ chọn nêu trên. rootMargin cho phép bạn chỉ định lề cho gốc, cho phép bạn tăng hoặc giảm diện tích dùng cho các giao lộ một cách hiệu quả. Các lề này được chỉ định bằng cách sử dụng một chuỗi kiểu CSS, tương tự như "10px 20px 30px 40px", chỉ định lề trên cùng, bên phải, dưới cùng và bên trái tương ứng. Tóm lại, cấu trúc tuỳ chọn IntersectionObserver cung cấp các tuỳ chọn sau:

new IntersectionObserver(entries => {/* … */}, {
  // The root to use for intersection.
  // If not provided, use the top-level document's viewport.
  root: null,
  // Same as margin, can be 1, 2, 3 or 4 components, possibly negative lengths.
  // If an explicit root element is specified, components may be percentages of the
  // root element size.  If no explicit root element is specified, using a
  // percentage is an error.
  rootMargin: "0px",
  // Threshold(s) at which to trigger callback, specified as a ratio, or list of
  // ratios, of (visible area / total area) of the observed element (hence all
  // entries must be in the range [0, 1]).  Callback will be invoked when the
  // visible ratio of the observed element crosses a threshold in the list.
  threshold: [0],
});

<iframe> thần kỳ

IntersectionObserver được thiết kế dành riêng cho các dịch vụ quảng cáo và tiện ích mạng xã hội, thường sử dụng các phần tử <iframe> và có thể hưởng lợi từ việc biết liệu các phần tử đó có hiển thị hay không. Nếu <iframe> quan sát thấy một trong các phần tử của nó, thì cả việc cuộn <iframe> lẫn cuộn cửa sổ chứa <iframe> sẽ kích hoạt lệnh gọi lại vào những thời điểm thích hợp. Tuy nhiên, trong trường hợp sau, rootBounds sẽ được đặt thành null để tránh rò rỉ dữ liệu giữa các nguồn gốc.

IntersectionObserver Không có vấn đề gì?

Xin lưu ý rằng IntersectionObserver không cố ý cung cấp độ phân giải pixel hoàn hảo hay độ trễ thấp. Việc sử dụng chúng để triển khai những nỗ lực như ảnh động phụ thuộc vào thao tác cuộn chắc chắn sẽ không thành công vì dữ liệu sẽ bị lỗi thời vào thời điểm bạn sử dụng dữ liệu đó. Nội dung giải thích có thêm thông tin chi tiết về các trường hợp sử dụng ban đầu của IntersectionObserver.

Tôi có thể làm được bao nhiêu việc trong lệnh gọi lại?

Tóm tắt: Việc dành quá nhiều thời gian cho lệnh gọi lại sẽ khiến ứng dụng bị trễ – tất cả các phương pháp thông thường đều áp dụng.

Hãy đi và giao nhau các phần tử của bạn

Trình duyệt hỗ trợ tốt cho IntersectionObserver, vì trình duyệt này có sẵn trong tất cả trình duyệt hiện đại. Nếu cần, bạn có thể sử dụng polyfill trong các trình duyệt cũ và có trong kho lưu trữ của WICG. Rõ ràng là bạn sẽ không nhận được lợi ích về hiệu suất khi sử dụng polyfill đó mà việc triển khai gốc sẽ mang lại cho bạn.

Bạn có thể bắt đầu sử dụng IntersectionObserver ngay! Hãy cho chúng tôi biết ý tưởng của bạn.