IntersectionObserver informuje, kiedy obserwowany element wchodzi do widocznego obszaru przeglądarki lub z niego wychodzi.
Powiedzmy, że chcesz śledzić, kiedy element w DOM wchodzi do widocznego obszaru. Możesz to zrobić, aby ładować obrazy z opóźnieniem w odpowiednim momencie lub dlatego, że chcesz wiedzieć, czy użytkownik faktycznie patrzy na określony baner reklamowy. Możesz to zrobić, podłączając zdarzenie przewijania lub używając okresowego timera i wywołania getBoundingClientRect()
w tym elemencie.
Takie podejście jest jednak bardzo powolne, ponieważ każde wywołanie funkcji getBoundingClientRect()
powoduje, że przeglądarka musi ponownie ułożyć całą stronę, co spowoduje znaczne spowolnienie działania witryny. Gdy wiesz, że Twoja witryna jest wczytywana w ramce iframe, a chcesz się dowiedzieć, kiedy użytkownik może zobaczyć dany element, sytuacja staje się prawie niemożliwa. Model pojedynczego źródła i przeglądarka nie pozwolą Ci uzyskać dostępu do żadnych danych ze strony internetowej zawierającej element iframe. Jest to typowy problem w przypadku reklam, które są często wczytywane za pomocą ramek iframe.
IntersectionObserver
został zaprojektowany, aby zwiększyć skuteczność testu widoczności. Jest dostępny we wszystkich nowoczesnych przeglądarkach. IntersectionObserver
informuje, kiedy obserwowany element wchodzi do widocznego obszaru przeglądarki lub z niego wychodzi.
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();
Przy użyciu domyślnych opcji funkcji IntersectionObserver
wywołanie zwrotne zostanie wywołane zarówno wtedy, gdy element częściowo wejdzie do widoku, jak i gdy całkowicie opuści widok.
Jeśli musisz obserwować wiele elementów, możesz i powinieneś to robić za pomocą tego samego wystąpienia IntersectionObserver
, wywołując funkcję observe()
kilka razy.
Do funkcji wywołania zwrotnego przekazywany jest parametr entries
, który jest tablicą obiektów IntersectionObserverEntry
. Każdy taki obiekt zawiera zaktualizowane dane dotyczące przecięcia 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 funkcji getBoundingClientRect()
w elemencie głównym, który domyślnie jest widocznym obszarem. boundingClientRect
to wynik wywołania funkcji getBoundingClientRect()
dla obserwowanego elementu. intersectionRect
to przecięcie tych 2 prostokątów, które określa, który fragment obserwowanego elementu jest widoczny. intersectionRatio
jest ściśle powiązana i pokazuje, ile elementu jest widoczne. Dzięki tym informacjom możesz teraz wdrażać funkcje takie jak wczytywanie komponentów w samym momencie, gdy mają się pojawić na ekranie. wydajnie,
IntersectionObserver
przesyłają dane asynchronicznie, a kod wywołania zwrotnego będzie wykonywany w głównym wątku. Specyfikacja określa też, że implementacje IntersectionObserver
powinny używać requestIdleCallback()
. Oznacza to, że połączenie z Twoim numerem jest połączeniem o niskim priorytecie i będzie wykonane przez przeglądarkę w czasie bezczynności. Jest to przemyślana decyzja projektowa.
Elementy div z przewijaniem
Nie jestem zwolennikiem przewijania w ramach elementu, ale nie jestem tu po to, aby oceniać, tak samo jak IntersectionObserver
. Obiekt options
przyjmuje opcję root
, która umożliwia zdefiniowanie alternatywy dla widoku jako elementu skojarzonego. Pamiętaj, że root
musi być przodkiem wszystkich obserwowanych elementów.
Przecięcie wszystkich rzeczy
Nie! Zły deweloper! To nie jest rozsądne wykorzystanie cykli procesora użytkownika. Weźmy na przykład nieskończony scroller: w takim przypadku zdecydowanie zalecamy dodanie do DOM elementów kontrolnych i obserwowanie ich (oraz ich recykling). Dodaj sentinela w pobliżu ostatniego elementu w przewijaniu nieskończonym. Gdy czujnik znajdzie się w polu widzenia, możesz użyć wywołania zwrotnego do załadowania danych, utworzenia kolejnych elementów, dołączenia ich do DOM i odpowiedniego przemieszczenia czujnika. Jeśli prawidłowo poddasz sentinelowi recyklingowi, nie musisz dodatkowo kontaktować się z observe()
. Aplikacja IntersectionObserver
nadal działa.
Więcej informacji
Jak już wspomnieliśmy, funkcja wywołania zwrotnego zostanie wywołana raz, gdy obserwowany element częściowo wejdzie do widoku, i jeszcze raz, gdy opuści widok. 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 tu przydaje się opcja threshold
. Umożliwia ona zdefiniowanie tablicy progów intersectionRatio
. Funkcja zwracana jest za każdym razem, gdy intersectionRatio
przekracza jedną z tych wartości. Wartością domyślną dla threshold
jest [0]
, co wyjaśnia działanie domyślne. Jeśli zmienimy wartość threshold
na [0, 0.25, 0.5, 0.75, 1]
, będziemy otrzymywać powiadomienia za każdym razem, gdy będzie widoczna dodatkowa ćwiartka elementu:
Czy są inne opcje?
Obecnie oprócz wymienionych powyżej opcji jest jeszcze tylko 1 dodatkowa opcja. rootMargin
umożliwia określenie marginesów dla głównego elementu, co pozwala zwiększyć lub zmniejszyć obszar używany do skrzyżowań. Te marginesy są określone za pomocą ciągu znaków w stylu CSS ("10px 20px 30px 40px"
), odpowiednio dla górnego, prawego, dolnego i lewego marginesu. Podsumowując, struktura opcji IntersectionObserver
udostępnia 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>
magic
IntersectionObserver
zostały zaprojektowane 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 wiedzy o tym, czy są widoczne. Jeśli <iframe>
obserwuje jeden ze swoich elementów, przewijanie <iframe>
oraz przewijanie okna zawierającego <iframe>
spowoduje wywołanie funkcji z powrotem w odpowiednich momentach. W tym drugim przypadku wartość rootBounds
zostanie ustawiona na null
, aby uniknąć wycieku danych z różnych źródeł.
O czym nie jest IntersectionObserver
?
Pamiętaj, że IntersectionObserver
nie jest celowo ani idealnie dokładny, ani o niskiej latencji. Ich użycie do implementacji takich rozwiązań jak animacje zależne od przewijania jest skazane na niepowodzenie, ponieważ do czasu, gdy zechcesz z nich skorzystać, dane będą nieaktualne. Więcej informacji o pierwotnych zastosowaniach IntersectionObserver
znajdziesz w tym artykule.
Jak wiele mogę zrobić podczas rozmowy zwrotnej?
Krótko i na temat: zbyt długi czas wywołania funkcji callback spowoduje opóźnienie aplikacji – obowiązują wszystkie standardowe praktyki.
Idźcie i skrzyżujcie elementy
IntersectionObserver
jest dobrze obsługiwany przez przeglądarki, ponieważ jest dostępny we wszystkich nowoczesnych przeglądarkach. W starszych przeglądarkach można użyć polyfilla, który jest dostępny w repozytorium WICG. Oczywiście nie uzyskasz korzyści związanych z wydajnością, jakie daje implementacja natywna.
Możesz zacząć korzystać z IntersectionObserver
już teraz. Powiedz nam, co udało Ci się znaleźć.