JS API Intersection Observer and lazy loading
Mapbox recently released Global View, which can run smoothly and smoothly on both Web and Mobile.
So I changed the map on my blog at the first time. Since this map is not on the first screen on my blog, considering the feelings of some mobile users, I decided to lazy load it, that is initialize the earth when the page scrolls to its position.
This problem has successfully become the lazy loading problem we often encounter. The traditional method is to listen to the scroll
event, and then use a method similar to getBoundingClientRect()
to obtain the coordinates of the object, and then perform various calculations to determine Whether the target element is present in the viewport. But because scroll
is triggered frequently, and the execution of getBoundingClientRect()
is also running on the main thread of the browser, it is prone to performance problems and is not so elegant. In this case our protagonist Intersection Observer API
shines!
1. What is Intersection Observer API
Intersection Observer API
is relatively concise and easy to understand,it consists of 2 parts observer
and observed element
. After specifying the relationship between the observer
and the observed element
, the observer
will pay close attention to the observed element
and call a callback function when certain conditions are met (configured through the observers
options`).
1.1 IntersectionObserver
We can initialize an Observer
with new IntersectionObserver(callback, options)
, for example:
// initialize
let options = {
root: document.querySelector('#box'),
rootMargin: '0px',
threshold: 1.0
}
const observer = new IntersectionObserver(callback, options);
// monitor element
const el = document.querySelector('#target') // element being monitored
observer.observe(el) // start listening for elements
1.1.1 options
options
are configuration parameters that mainly tell the observer
when the callback should be triggered:
root
is the observer element, must be the parent element of the observed element, if not specified, it defaults to the browser window.rootMargin
is similar to CSSmargin
, can be set to a value such as10px
,10px 20px 10px 20px
, default is0
threshold
is used to control how far the observed element intersects the observer's viewport to trigger the callback. It can be a number between 0-1, or an array of numbers between 0-1, such as[0.1,0.5,1.0]
. For details, please refer to the elevator example below.
To start our elevator example, the elevator door of a certain floor (corresponding to the root
in options
) is equivalent to an observer
, and the elevator box is equivalent to an observed element
. As a elevator developer, we can make the elevator run according to our needs. For example, when the elevator just reaches this floor (rootMargin
), the bell will ring to remind the waiting users, and when the elevator completely reaches the floor (threshold
), turn on the elevator door.
Figure 1: Example of root
and rootMargin
Figure 2: For an upward elevator, when the top reaches the bottom of the elevator door(Include the margin), the threshold
is 0 (the elevator door must not be opened at this time, otherwise...), when the elevator completely overlaps the elevator door, the threshold
is 1 (The elevator door can now be opened with confidence... ahem, right? Seems we missed the margin)
Figure 3: If threshold
is an array, a callback will be triggered when any value satisfies the condition
1.1.2 callback
The callback
method will be triggered when:
- The
observed
enters or leaves the viewport. - When the
Observed Element
is bound, please pay special attention to this trigger when the initial binding is performed, and check whether theObserved element
is in the viewport or not throughIntersectionObserverEntry.isIntersecting
.
The callback
method accepts 2 parameters entries
and observer
:
entries
is a collection of instances of relatedobserved elements
(IntersectionObserverEntry)observer
is an instance ofObserver
(IntersectionObserver)
1.1.3 IntersectionObserverEntry
IntersectionObserverEntry (the Observed Element
instance) contains the following read-only properties:
boundingClientRect
: Returns DOMRectReadOnly. As same as Element.getBoundingClientRect().intersectionRatio
:Returns the ratio of intersectionRect and boundingClientRect.intersectionRect
: Returns a [DOMRectReadOnly describing the intersection area of the root and target elements.isIntersecting
:Returns a boolean value that returns true if the target element intersects the root of the intersection observer object. If it returns true, the IntersectionObserverEntry describes the state of the transition to the intersection; if it returns false, Then it can be judged from this that the transition is from a cross state to a non-cross state.rootBounds
: Returns a DOMRectReadOnly describing the root in the intersection observer.target
: The element (Element) that changes the area of intersection with the root.time
: Returns a timestamp from the origin of the IntersectionObserver to the time the intersection was triggered.
1.1.3 IntersectionObserverEntry
IntersectionObserverEntry (an observer
instance) contains the following read-only properties: root
, rootMargin
, thresholds
, and the following methods:
.disconnect()
: stop listening work.observer(targetElement)
: start listening to an element.takeRecords()
: returns a list of all observed objects.unobserve(target)
: stop listening to a specific target
2. Typical application scenarios of Intersection Observer
2.1 Lazy loading of images
This may be one of the most common application scenarios. The specific process can be: by creating the page viewport as an observer
object ➡️ Binding all image placeholders in the page ➡️ After the observer callback is triggered ➡️ Traversal Matched objects ➡️ Use isIntersecting
judgment to replace the placeholder with the actual image. I won't go into too much detail here.
2.2 Scroll to the bottom of the page with autoload function
We often see the automatic loading dynamic function of scrolling to the bottom of the page, which can also be cleverly implemented by Intersection Observer: place an observed element similar to load more
at the bottom of the page. When this element appears in the field of view, Call the API to get more data to fill in.
I wrote a simple Demo:
3. Bonus
While consulting related materials, I found some good demos or documents and shared them with you:
3.1. Example of Intersection Observer API Principle
Find a good example in codepen to fully understand the relevant parameters of the Intersection Observer API in an interactive way
Demo Author https://codepen.io/michellebarker
3.2. How to use it in React - "Lazy Loading Images in React"
If you are using React, here is a good article on Lazy Loading Using the Intersection Observer API with React, keywords useEffect
, useRef