IntersectionObservers cho bạn biết khi nào 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.
Giả sử bạn muốn theo dõi thời điểm một phần tử trong DOM chuyển vào khung nhìn hiển thị. Bạn nên thực hiện 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ự xem một biểu ngữ quảng cáo nhất định hay không. Bạn có thể làm việc này bằng cách kết nối sự kiện cuộn hoặc sử dụng bộ tính giờ định kỳ rồi gọi getBoundingClientRect()
trên phần tử đó.
Tuy nhiên, phương pháp này quá chậm vì mỗi lệnh gọi đến getBoundingClientRect()
sẽ buộc trình duyệt bố cục lại toàn bộ trang và sẽ khiến trang web của bạn bị giật đáng kể. Các vấn đề gần như không thể xảy ra khi bạn biết trang web của mình đang được tải bên trong iframe và bạn muốn biết khi nào người dùng có thể thấy một phần tử. Mô hình nguồn gốc đơn lẻ 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 đề phổ biến đối với quảng cáo, chẳng hạn như quảng cáo thường xuyên được tải bằng iframe.
Giúp thử nghiệm chế độ hiển thị này hiệu quả hơn là mục tiêu IntersectionObserver
được thiết kế cho và nó đã có trong 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 đi vào hoặc thoát khỏi khung nhìn của trình duyệt.

Cách tạo IntersectionObserver
API này khá nhỏ và được mô tả tốt nhất bằng cách sử dụ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 của bạn 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ử hoàn toàn rời khỏi khung nhìn.
Nếu cần quan sát nhiều phần tử, bạn có thể 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, là một mảng các đối tượng IntersectionObserverEntry
. Mỗi đối tượng như vậy chứa dữ liệu nút giao được cập nhật cho một trong các phần tử được quan sát của bạn.
🔽[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 sẽ hiển thị một cách hiệu quả. intersectionRatio
có liên quan chặt chẽ và cho bạn biết lượng của phần tử hiển thị. Nhờ có thông tin này, giờ đây bạn có thể triển khai các tính năng như tải tài sản kịp thời trước khi chúng xuất hiện trên màn hình. Hiệu quả.

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, quy cách này thực sự cho biết các quy trình triển khai IntersectionObserver
nên 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ẽ đượ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ế sáng suốt.
Di chuyển di chuyển
Tôi không phải là người thích cuộn bên trong một phần tử, nhưng tôi không ở đây để đánh giá và IntersectionObserver
cũng không phải là như vậy. Đối tượng options
sử dụng tuỳ chọn root
cho phép bạn xác định một phương án 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à đối tượng cấp trên của tất cả các phần tử được quan sát.
Giao cắt mọi thứ!
Không đâu! Nhà phát triển chưa tốt! Thao tác này không lưu ý đến việc sử dụng chu kỳ CPU của người dùng. Hãy cùng xem ví dụ về một 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ế!) những lệnh này. Bạn nên thêm người canh gần mục cuối cùng trong trình cuộn vô hạn. Khi người canh đó 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 canh gác cho phù hợp. Nếu tái chế người canh đúng cách, bạn không cần thực hiện thêm lệnh gọi nào đến observe()
. IntersectionObserver
vẫn hoạt động.

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 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 cho câu hỏi "Phần tử X có đang hiển thị không?". Tuy nhiên, trong một số trường hợp sử dụng, điều này có thể là chưa đủ.
Đó là lúc tuỳ chọn threshold
phát huy tác dụng. Hàm 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 của bạn 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
là [0]
, điều này giải thích hành vi mặc định. Nếu thay đổi threshold
thành [0, 0.25, 0.5, 0.75, 1]
, chúng tôi sẽ nhận được thông báo mỗi khi có thêm một phần tư của phần tử hiển thị:

Bạn còn cách nào khác không?
Hiện tại, chỉ còn một lựa chọn khác ngoài các lựa chọn nêu trên. rootMargin
cho phép bạn chỉ định lề cho gốc, giúp bạn tăng hoặc thu nhỏ diện tích sử dụng cho các giao lộ một cách hiệu quả. Các lề này được chỉ định bằng một chuỗi kiểu CSS, á la "10px 20px 30px 40px"
, chỉ định lề trên, phải, dưới và 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>
kỳ diệu
Các IntersectionObserver
được thiết kế riêng cho dịch vụ quảng cáo và tiện ích con của mạng xã hội, thường sử dụng các phần tử <iframe>
và có thể hưởng lợi khi biết các phần tử này có nằm trong khung 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>
cũng như cuộn cửa sổ chứa <iframe>
đều 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, đối với trường hợp sau, rootBounds
sẽ được đặt thành null
để tránh rò rỉ dữ liệu trên các nguồn gốc.
Nội dung của IntersectionObserver
Không là gì?
Điều cần lưu ý là IntersectionObserver
không có chủ đích hoàn hảo về mặt pixel, cũng không có độ trễ thấp. Việc sử dụng chúng để triển khai các tính năng như ảnh động phụ thuộc vào thao tác cuộn sẽ chắc chắn sẽ không thành công, vì dữ liệu (thực ra là) sẽ bị lỗi thời vào thời điểm bạn sử dụng. Phần 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 bao nhiêu việc trong lệnh gọi lại?
Video ngắn ngọt ngào: 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 phổ biến đều áp dụng.
Hãy tiến lên và giao thoa các thành phần của bạn
Trình duyệt hỗ trợ IntersectionObserver
rất tốt, 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ể dùng polyfill trong các trình duyệt cũ và có trong kho lưu trữ của WICG. Rõ ràng, bạn sẽ không được hưởng lợi về hiệu suất khi sử dụng đoạn mã polyfill mà phương thứ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 bây giờ! Hãy cho chúng tôi biết ý định của bạn.