1, Use
The visible area is the area visible to the naked eye of our web browsing device, as shown in the figure below
In daily development, we often need to judge whether the target element is within the window or the distance from the window is less than a value (e.g. 100 px), so as to realize some common functions, such as:
-
Lazy loading of pictures
-
Infinite scrolling of lists
-
Calculate the exposure of advertising elements
-
Clickable link preload
2, Implementation mode
There are three common methods to judge whether an element is in the visual area:
-
offsetTop,scrollTop
-
getBoundingClientRect
-
Intersection Observer
offsetTop,scrollTop
offsetTop, the pixel distance from the upper outer border of the element to the upper inner border containing the element. Other offset attributes are shown in the following figure:
Let's learn more about clientWidth and clientHeight:
-
clientWidth: the width of the element content area plus the width of the left and right inner margins, that is, clientWidth = content + padding
-
clientHeight: the height of the element content area plus the height of the upper and lower inner margins, that is, clientHeight = content + padding
You can see that none of the client elements include the outer margin
Finally, the properties of the scroll series are as follows:
-
scrollWidth and scrollHeight It is mainly used to determine the actual size of element content
-
scrollLeft and scrollTop Property can determine the current scrolling state of an element or set the scrolling position of an element
-
-
Vertical scroll scrollTop > 0
-
horizontal scroll scrollLeft > 0
-
-
The element's scrollLeft and scrollTop Set to 0 to reset the scrolling position of the element
be careful
-
The above properties are read-only, and each access must be restarted
Here's how to realize judgment:
The formula is as follows:
el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
Code implementation:
function isInViewPortOfOne (el) { // viewPortHeight Compatible with all browser writing methods const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight const offsetTop = el.offsetTop const scrollTop = document.documentElement.scrollTop const top = offsetTop - scrollTop return top <= viewPortHeight }
getBoundingClientRect
The return value is a DOMRect object with left, top, right, bottom, x, y, width, and height attribute
const target = document.querySelector('.target'); const clientRect = target.getBoundingClientRect(); console.log(clientRect); // { // bottom: 556.21875, // height: 393.59375, // left: 333, // right: 1017, // top: 162.625, // width: 684 // }
The corresponding relationship diagram of attributes is as follows:
When the page scrolls, the top and left attribute values will change accordingly
If an element is in the window, it must meet the following four conditions:
-
top is greater than or equal to 0
-
left is greater than or equal to 0
-
bottom is less than or equal to the window height
-
right is less than or equal to the window width
The implementation code is as follows:
function isInViewPort(element) { const viewWidth = window.innerWidth || document.documentElement.clientWidth; const viewHeight = window.innerHeight || document.documentElement.clientHeight; const { top, right, bottom, left, } = element.getBoundingClientRect(); return ( top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight ); }
Intersection Observer
Intersection Observer That is, the overlap observer. From this name, we can see that it is used to judge whether two elements overlap. Because there is no event listening, the performance is much better than getBoundingClientRect
The usage steps are mainly divided into two steps: creating an observer and passing in an observer
Create observer
const options = { // Represents the proportion of overlapping area in the observed, from 0 - one Value, // one Indicates full inclusion threshold: 1.0, root:document.querySelector('#scrollArea') // Must be a parent of the target element }; const callback = (entries, observer) => { ....} const observer = new IntersectionObserver(callback, options);
The observer is created through the new IntersectionObserver Observer, parameters passed in callback When the overlap ratio exceeds threshold Will be executed`
The common attributes of the callback function are as follows:
// Omitted from the previous code callback const callback = function(entries, observer) { entries.forEach(entry => { entry.time; // Trigger time entry.rootBounds; // The position rectangle of the root element, in this case the window position entry.boundingClientRect; // The position of the observer is held entry.intersectionRect; // Position rectangle of overlapping area entry.intersectionRatio; // The proportion of overlapping area in the area of the observed person (if the observed person is not rectangular, it is also calculated according to the rectangle) entry.target; // Observed }); };
Incoming observer
adopt observer.observe(target) This line of code can simply register the observer
const target = document.querySelector('.target'); observer.observe(target);
3, Case analysis
Implementation: a long list of 100000 nodes is created. When the nodes roll into the window, the background will change from red to yellow
The Html structure is as follows:
<div class="container"></div>
css style is as follows:
.container { display: flex; flex-wrap: wrap; } .target { margin: 5px; width: 20px; height: 20px; background: red; }
Insert 1000 elements into container
const $container = $(".container"); // insert one hundred thousand individual < div class="target"></div> function createTargets() { const htmlString = new Array(100000) .fill('<div class="target"></div>') .join(""); $container.html(htmlString); }
Here, first use the getBoundingClientRect method to determine whether the element is in the visual area
function isInViewPort(element) { const viewWidth = window.innerWidth || document.documentElement.clientWidth; const viewHeight = window.innerHeight || document.documentElement.clientHeight; const { top, right, bottom, left } = element.getBoundingClientRect(); return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight; }
Then start listening to the scroll event to determine which elements on the page are in the visual area. If they are in the visual area, set the background color to yellow
$(window).on("scroll", () => { console.log("scroll !"); $targets.each((index, element) => { if (isInViewPort(element)) { $(element).css("background-color", "yellow"); } }); });
Through the above methods, we can see that the color of the visual area will turn yellow, but we can obviously see the phenomenon of jamming. The reason is that we bind the scroll event. The scroll event is accompanied by a large number of calculations, which will cause a waste of resources
The same functions are also realized in the form of Intersection Observer
First create an observer
const observer = new IntersectionObserver(getYellow, { threshold: 1.0 });
The getYellow callback function changes the background color as follows:
function getYellow(entries, observer) { entries.forEach(entry => { $(entry.target).css("background-color", "yellow"); }); }
Finally, the observer is passed in, that is, the. target element
$targets.each((index, element) => { observer.observe(element); });
You can see that the function is also completed, and the page will not get stuck