IntersectionObservers informują, kiedy obserwowany element pojawia się w obszarze widocznym przeglądarki lub go opuszcza.
Załóżmy, że chcesz śledzić, kiedy element w DOM pojawia się w widocznym obszarze wyświetlania. Możesz to zrobić, aby leniwie ładować obrazy w odpowiednim momencie lub gdy chcesz wiedzieć, czy użytkownik rzeczywiście patrzy na dany baner reklamowy. Możesz to zrobić, podłączając zdarzenie przewijania lub używając okresowego licznika czasu i wywołując getBoundingClientRect() na tym elemencie.
To podejście jest jednak bardzo powolne, ponieważ każde wywołanie funkcji getBoundingClientRect() zmusza przeglądarkę do ponownego ułożenia całej strony i powoduje znaczne opóźnienia w jej działaniu. Sprawa staje się niemal niemożliwa, gdy wiesz, że Twoja witryna jest wczytywana w elemencie iframe, i chcesz wiedzieć, kiedy użytkownik może zobaczyć dany element. Model pojedynczego źródła i przeglądarka nie pozwolą Ci uzyskać dostępu do żadnych danych ze strony internetowej, która zawiera element iframe. Jest to częsty problem w przypadku reklam, które są często wczytywane za pomocą elementów iframe.
Interfejs IntersectionObserver został zaprojektowany, aby zwiększyć wydajność tego testu widoczności, i jest dostępny we wszystkich nowoczesnych przeglądarkach. IntersectionObserver informuje, kiedy obserwowany element pojawia się w obszarze widocznym w przeglądarce lub go opuszcza.
Jak utworzyć IntersectionObserver
Interfejs API jest dość mały i najlepiej opisać go na przykładzie:
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();
Jeśli użyjesz domyślnych opcji dla IntersectionObserver, wywołanie zwrotne zostanie wywołane zarówno wtedy, gdy element pojawi się częściowo w widoku, jak i wtedy, gdy całkowicie opuści widoczny obszar.
Jeśli musisz obserwować wiele elementów, możesz i powinieneś obserwować je za pomocą tej samej instancji IntersectionObserver, wywołując observe() wielokrotnie.
Do wywołania zwrotnego przekazywany jest parametr entries, który jest tablicą obiektów IntersectionObserverEntry. Każdy taki obiekt zawiera zaktualizowane dane o przecięciu dla jednego z obserwowanych elementów.
🔽[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 to wynik wywołania getBoundingClientRect() w elemencie głównym, którym domyślnie jest widoczny obszar. boundingClientRect to wynik wywołania getBoundingClientRect() na obserwowanym elemencie. intersectionRect to część wspólna tych 2 prostokątów, która wskazuje, która część obserwowanego elementu jest widoczna. intersectionRatio jest ściśle powiązany z tym wskaźnikiem i informuje, jaka część elementu jest widoczna. Dzięki tym informacjom możesz wdrażać funkcje takie jak wczytywanie zasobów tuż przed ich wyświetleniem na ekranie. Wydajnie.
IntersectionObserver dostarczają dane asynchronicznie, a kod wywołania zwrotnego będzie uruchamiany w głównym wątku. Dodatkowo specyfikacja wskazuje, że implementacje IntersectionObserver powinny używać requestIdleCallback(). Oznacza to, że wywołanie podanej funkcji wywołania zwrotnego ma niski priorytet i zostanie wykonane przez przeglądarkę w czasie bezczynności. Jest to świadoma decyzja projektowa.
Przewijane elementy div
Nie jestem fanem przewijania wewnątrz elementu, ale nie jestem tu po to, żeby oceniać, podobnie jak IntersectionObserver. Obiekt options przyjmuje opcję root, która pozwala zdefiniować alternatywę dla widocznego obszaru jako elementu głównego. Pamiętaj, że root musi być elementem nadrzędnym wszystkich obserwowanych elementów.
Przecięcie wszystkich elementów
Nie! Bad developer! Nie jest to rozsądne wykorzystanie cykli procesora użytkownika. Weźmy na przykład nieskończone przewijanie: w tym scenariuszu zdecydowanie zaleca się dodanie do modelu DOM znaczników i ich obserwowanie (oraz ponowne wykorzystywanie). Dodaj element wartowniczy blisko ostatniego elementu w nieskończonym przewijaniu. Gdy ten element pojawi się w widoku, możesz użyć wywołania zwrotnego, aby wczytać dane, utworzyć kolejne elementy, dołączyć je do modelu DOM i odpowiednio zmienić pozycję elementu sentinel. Jeśli prawidłowo poddasz recyklingowi obiekt sentinel, nie musisz dodatkowo wywoływać metody observe(). IntersectionObserver nadal działa.
Więcej aktualizacji
Jak wspomnieliśmy wcześniej, wywołanie zwrotne zostanie uruchomione raz, gdy obserwowany element pojawi się częściowo w widoku, i drugi raz, gdy opuści on widoczny obszar. W ten sposób IntersectionObserver odpowiada na pytanie: „Czy element X jest widoczny?”. W niektórych przypadkach może to jednak nie wystarczyć.
Właśnie do tego służy opcja threshold. Umożliwia zdefiniowanie tablicy progów intersectionRatio. Wywołanie zwrotne będzie wywoływane za każdym razem, gdy intersectionRatio przekroczy jedną z tych wartości. Domyślna wartość parametru threshold to [0], co wyjaśnia działanie domyślne. Jeśli zmienimy threshold na [0, 0.25, 0.5, 0.75, 1], będziemy otrzymywać powiadomienia za każdym razem, gdy widoczna stanie się kolejna ćwiartka elementu:
Czy są inne opcje?
Obecnie dostępna jest tylko jedna dodatkowa opcja oprócz tych wymienionych powyżej. rootMargin pozwala określić marginesy elementu głównego, co umożliwia powiększenie lub zmniejszenie obszaru używanego do przecięć. Te marginesy są określane za pomocą ciągu znaków w stylu CSS, np. "10px 20px 30px 40px", który określa odpowiednio górny, prawy, dolny i lewy margines. Podsumowując, struktura opcji IntersectionObserver oferuje te opcje:
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> magia
IntersectionObserver zostały zaprojektowane specjalnie z myślą o usługach reklamowych i widżetach sieci społecznościowych, które często używają elementów <iframe> i mogą korzystać z informacji o tym, czy są widoczne. Jeśli element <iframe> obserwuje jeden ze swoich elementów, zarówno przewijanie elementu <iframe>, jak i przewijanie okna zawierającego element <iframe> spowoduje wywołanie funkcji zwrotnej w odpowiednich momentach. W tym drugim przypadku parametr rootBounds zostanie ustawiony na null, aby uniknąć wycieku danych między źródłami.
Czego nie dotyczy IntersectionObserver?
Pamiętaj, że IntersectionObserver nie jest celowo ani idealny pod względem pikseli, ani nie ma niskiego opóźnienia. Używanie ich do implementowania takich rozwiązań jak animacje zależne od przewijania nie powiedzie się, ponieważ dane będą nieaktualne, zanim zostaną użyte. Więcej informacji o pierwotnych przypadkach użycia interfejsu IntersectionObserver znajdziesz w objaśnieniu.
Ile pracy mogę wykonać w wywołaniu zwrotnym?
Krótko i na temat: zbyt dużo czasu spędzonego w wywołaniu zwrotnym spowoduje opóźnienia w aplikacji – obowiązują wszystkie typowe praktyki.
Przecinanie elementów
Obsługa IntersectionObserver w przeglądarkach jest dobra, ponieważ jest dostępna we wszystkich nowoczesnych przeglądarkach. W razie potrzeby w starszych przeglądarkach można użyć kodu polyfill, który jest dostępny w repozytorium WICG. Oczywiście nie uzyskasz korzyści związanych z wydajnością, które zapewnia natywna implementacja.
Możesz zacząć korzystać z usługi IntersectionObserver już teraz. Powiedz nam, co udało Ci się wymyślić.