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 chuyển vào khung nhìn hiển thị. Bạn nên làm việc này để có thể tải lười hình ảnh đúng lúc 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 rất chậm vì mỗi lệnh gọi đến getBoundingClientRect() buộc trình duyệt phải sắp xếp lại toàn bộ trang và sẽ gây ra hiện tượng giật đáng kể cho trang web của bạn. 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à vấn đề thường gặp đối với quảng cáo, chẳng hạn như quảng cáo thường đượ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 đưa vào tất cả trình duyệt hiện đại. IntersectionObserver cho bạn biết thời điểm một phần tử được quan sát vào hoặc ra 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 của bạn, đây là một mảng 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 hiệu quả 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ử. Với thông tin này, bạn hiện có thể triển khai các tính năng như tải thành phần đúng lú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ự cho biết rằng các hoạt động triển khai IntersectionObserver phải sử dụng requestIdleCallback(). Điều này có nghĩa 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ẽ do trình duyệt thực hiện trong thời gian rảnh. Đâ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 có ý định đá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 tồi! Đó không phải là cách sử dụng chu kỳ CPU của người dùng một cách hợp lý. Hãy lấy ví dụ về một thanh cuộn vô hạn: Trong trường hợp đó, bạn nên thêm sentinel vào DOM và quan sát (và tái chế!) các sentinel đó. 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 trình quan sát đó 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 các mục đó vào DOM và định vị lại trình quan sát cho phù hợp. Nếu bạn tái chế đúng cách trình quan sát, bạn không cần gọi thêm observe(). IntersectionObserver tiếp tục hoạt động.

Thanh 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 bạn cần đến tuỳ chọn threshold. 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ử khác hiển thị:

Ả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. Các dịch vụ này 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ó đang hiển thị hay không. Nếu <iframe> quan sát một trong các phần tử của nó, thì cả việc cuộn <iframe> cũng như cuộn cửa sổ chứa <iframe> sẽ kích hoạt lệnh gọi lại vào 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 là 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 các lớp này để triển khai các hoạt động như ảnh động phụ thuộc vào thao tác cuộn sẽ không thành công, vì dữ liệu sẽ – nói một cách nghiêm ngặt – đã lỗi thời vào thời điểm bạn sử dụng. 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 của bạn 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

Hỗ trợ trình duyệt cho IntersectionObserver rất tốt, vì tính năng này có 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.