Zhengzhou flood in July this year, the epidemic in August, the company moved in December, after the New Year’s day is the epidemic! Really not easy! This is not now the company Intranet, at home do not let the company computer, so can not write the company code at home! Whether studying at home will pay is unknown! And by the way,
1. The meaning of image lazy loading
Image delay loading is a very important performance optimization method in real projects. If you don’t do the time delay of loading images, that also page rendering time, as well as the image resource requests, rendering is done, it will hinder the page rendering progress, for the first time to load the page is slow, lazy loading can feed page loading speed on one hand, on the other hand can reduce unnecessary network consumption
** The image area is occupied by the default background image (background color) before the actual image is loaded
** First screen: ** First load other data on the first screen and wait for other data to be loaded before loading the real picture
Other screens: Scroll to the corresponding area (once on the screen, half out, completely on the screen) before loading the real image
2. Image lazy loading scheme 1
During the browser scroll bar (page scrolling), while waiting for the image to fully appear in the visible window, we load the actual image, “This is a non-first screen image
Calculate the distance A from the bottom of the box to the top of the body and compare it with the distance B from the bottom of the browser to the top of the body. If A<=B, we can load the image
WechatIMG174
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<style>
* {
margin: 0;
}
.imageLazyBox {
width: 236px;
height: 420px;
background: url(./images/loading.gif) no-repeat center center #eee;
background-size: 100px 100px;
margin: 1000px 0px;
}
.imageLazyBox img {
width: 100%;
height: 100%;
/* Start image hiding: Because in Internet Explorer, if the SRC is empty or the image is loaded incorrectly, the image is not hidden, it will show an X effect, so it is better to hide the image before it is loaded. After loading the actual image, you need to tell it to display:blok; In this way, the backflow resink of DOM is triggered, and performance consumption is relatively large. transition:opacity: .3s; -> Recommended scheme: on the one hand, after loading the real picture, we only need to set opacity:1; This, on the one hand, does not cause dom backflow and reaggregation, and on the other hand, cSS3 can achieve the effect of asymptotic */
opacity: 0;
transition: opacity 1s;
/* display: none; * /
}
</style>
<body>
<div class="imageLazyBox">
<img src="" alt="" lazy-image="./images/img1.jpeg">
</div>
</body>
</html>
<script>
// Image lazy loading method processing
function imageLazyFun(imageLazyBox) {
let imageItem = imageLazyBox.querySelector('img'),
lazy_image = imageItem.getAttribute('lazy-image')
imageItem.src = lazy_image
imageItem.onload = function () {
imageItem.style.opacity = 1
}
imageItem.removeAttribute('lazy-image');
imageItem.isLoad = true;
}
let imageLazyBox = document.querySelector(".imageLazyBox"),
imageItem = imageLazyBox.querySelector('img'),
HTML = document.documentElement;
// Get the distance of an element from the top of the body
function offset(element) {
let l = element.offsetLeft,
t = element.offsetTop,
p = element.offsetParent;
while(p && p.tagName ! = ='body') {
if (!/MSIE 8/.test(navigator.userAgent)) {
l += p.clientLeft;
t += p.clientTop;
}
l += p.offsetLeft;
t += p.offsetTop;
p = p.offsetParent;
}
return {
top: t,
left: l
}
}
// Intercepting function
let throttle = function throttle(fn, wait) {
let timeout = null.// Timer variable
result = null.// Result of last execution
previous = 0; // The time of the last execution
return function anymouse(. args) {
let now = new Date,
context = this;
let remaining = wait - (now - previous);
// There is no time to clear the content of the last execution
// console.log("Shiji",remaining);
if (remaining <= 0) {
clearTimeout(timeout);
previous = now;
result = fn.apply(context, args);
// First execution
} else if(! timeout) { timeout =setTimeout(() = > {
previous = new Date;
result = fn.apply(context, args)
}, wait)
}
// console.log(result)
return result
}
}
// The execution frequency is too high to do the function interception
window.onscroll = throttle(function () {
console.log("Well, I did a flow stopper.")
if (imageItem.isLoad) return
let A = offset(imageLazyBox).top + imageLazyBox.offsetHeight,
B = HTML.clientHeight + HTML.scrollTop;
if (A <= B) {
console.log("ok") imageLazyFun(imageLazyBox); }},500)
</script>
Copy the code
3. Image lazy loading scheme 2 using getBoundingClientRect ()
GetBoundingClientRect is used to get the set of positions of an element relative to the view. The set has properties like top, right, bottom, and left.
All you need to do is change the criteria
window.onscroll = throttle(function () {
console.log("Well, I did a flow stopper.")
if (imageItem.isLoad) return
// let A = offset(imageLazyBox).top + imageLazyBox.offsetHeight,
// B = HTML.clientHeight + HTML.scrollTop;
let A = imageLazyBox.getBoundingClientRect().bottom;
B = HTML.clientHeight
if (A <= B) {
console.log("ok") imageLazyFun(imageLazyBox); }},500)
Copy the code
4. Scheme three realizes delayed loading based on IntersectionObserver
concept
The IntersectionObserver interface (which is part of the IntersectionObserver API) provides developers with a way to asynchronously monitor the intersectionstate of a target element with its ancestors or viewports. Ancestor elements and viewports are called roots.
This is an official concept on MDN, and it looks professional to post it
Important: the way to monitor the cross state of the target element with its ancestor or window is to see if an element is visible in the window. **
API
var io = new IntersectionObserver(callback, options)
Copy the code
It’s a simple constructor.
The above code returns an instance of IntersectionObserver, callback is the callback function when the visibility of the element changes, and Options are some configuration items (optional).
options
root
The root element for viewing, which is the browser viewport by default, can also be specified as a specific element, which must be a child of the specified element
threshold
An array that specifies the crossover ratio and determines when to trigger the callback function. The default is [0].
const options = {
root: null.threshold: [0.0.5.1]}var io = new IntersectionObserver(callback, options)
io.observe(document.querySelector('img'))
Copy the code
rootMargin
To increase or decrease the size of the window, use the CSS definition method with the top, right, bottom and left values at 10px, 10px, 30px and 20px
Const options = {root: document.querySelector('.box'), threshold: [0, 0.5, 1], rootMargin: '30px 100px 20px'}Copy the code
Let’s look at the picture for the sake of understanding
First of all, what is the blue line? It is the root element we defined. We added the rootMargin property to make the window larger. The dashed line is the window now, so the element is now inside the window.
Thus, the root element is an absolute window only when rootMargin is empty.
Having said simple options, let’s look at callback.
callback
The callback function fires twice, both when the element enters the window (when it becomes visible) and when it leaves the window (when it becomes invisible)
Var IO = new IntersectionObserver((entries)=>{console.log(entries)}) IO. Observe ($0) // Observe the DOMCopy the code
The result is as follows
We can see a entries callback function parameters, it is a IntersectionObserverEntry array of objects, and then we focused on the IntersectionObserverEntry object
IntersectionObserverEntry
IntersectionObserverEntry observation elements of information, there are seven attributes.
BoundingClientRect obtains the result of the rectangle information of the target element based on getBoundingClientRect(), which obtains the result intersectionRatio value of the intersecting area and target element Less than or equal to zero when intersectionRect/boundingClientRect not visible intersectionRect target element and rectangular information window (root) intersect Can be referred to as regional intersection isIntersecting target element is currently visible The Boolean value is shown as true rootBounds rectangle of the root element, which is not specified to be the rectangle of the current viewport. Target The target element to observe. Time Returns a timestamp from the time of IntersectionObserver to the time when IntersectionObserver is triggered
Key points: intersectionRatio and isIntersecting are used to judge whether elements are visible.
Trigger time of IntersectionObserver
Default: once when the DOM is first listened on, once when the element appears on the page, and once when the element disappears completely
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<style>
* {
margin: 0;
}
.imageLazyBox {
width: 236px;
height: 420px;
background: url(./images/loading.gif) no-repeat center center #eee;
background-size: 100px 100px;
margin: 1000px 0px;
}
.imageLazyBox img {
width: 100%;
height: 100%;
/* Start image hiding: Because in Internet Explorer, if the SRC is empty or the image is loaded incorrectly, the image is not hidden, it will show an X effect, so it is better to hide the image before it is loaded. After loading the actual image, you need to tell it to display:blok; In this way, the backflow resink of DOM is triggered, and performance consumption is relatively large. transition:opacity: .3s; -> Recommended scheme: on the one hand, after loading the real picture, we only need to set opacity:1; This, on the one hand, does not cause dom backflow and reaggregation, and on the other hand, cSS3 can achieve the effect of asymptotic */
opacity: 0;
transition: opacity 1s;
/* display: none; * /
}
</style>
<body>
<div class="imageLazyBox">
<img src="" alt="" lazy-image="./images/img1.jpeg">
</div>
</body>
</html>
<script>
function imageLazyFun(imageLazyBox) {
let imageItem = imageLazyBox.querySelector('img'),
lazy_image = imageItem.getAttribute('lazy-image')
imageItem.src = lazy_image
imageItem.onload = function () {
imageItem.style.opacity = 1
}
imageItem.removeAttribute('lazy-image');
imageItem.isLoad = true;
}
let imageLazyBox = document.querySelector(".imageLazyBox");
let ob = new IntersectionObserver(changes= > {
// Cross information between the DOM element we are listening for and the visual window
let item = changes[0];
target = item.target;
// The box is fully in the viewport
if (item.isIntersecting) {
// The box is fully in the viewport
imageLazyFun(target);
// This element is loaded lazily once, and then no longer needs to be listened for
ob.unobserve(target)
}
});
// Listen for dom elements
ob.observe(imageLazyBox)
// Remove the listener
// ob.unobserve(imageLazyBox)
</script>
Copy the code
5. There are four schemes for delayed image loading, but future methods are incompatible
Loading =”lazy” browsers are less compatible
Browser compatibility query url
<div class="imageLazyBox">
<img src="./images/img1.jpeg" loading="lazy" >
</div>
Copy the code
6. Comparison of advantages and disadvantages of several image lazy loading methods
GetBoundingClientRect has less computation than the first method, but getBoundingClientRect is not compatible and the first method is suitable for mobile terminal, both of which use window.onscroll method, so you need to write your own intercepting function to optimize performance
Compared with the window.onscroll method, IntersectionObserver is more convenient and has better performance and does not need its own throttling processing