Offer to come, dig friends take it! I am participating in the 2022 Spring Recruit Punch card activity. Click here for details.
Sometimes our front-end pages may contain a lot of images, such as some shopping sites or image sites. Page picture more, load picture more, the server pressure will be very big. Not only does it affect page rendering speed, but it also wastes bandwidth. For example, a 1 Megabyte image with 1000 people accessing it at the same time will generate 1 gigabyte of bandwidth. In order to solve these problems and improve the user experience, lazy loading has appeared. What is lazy loading? When entering the page, only the image resources in the visual area are requested. Lazy, I will not give you all the pictures, you want to see how many, I will give you how many.
implementation
HTML implementation
The easiest way to do this is to load the IMG tag with loading= lazy
<img src="img/1.jpg" loading="lazy" />
Copy the code
Js implementation
We use js to monitor the scrolling of the page to determine whether the current picture is in the visible area:
- Get all the images dom;
- Traverse each picture to determine whether the current picture is in the range of visual area;
- If so, set the SRC attribute for the image.
- Bind scroll event to monitor the event.
When the page is initialized, the SRC of the image is placed on the data-src attribute, and the data-src attribute is assigned to the SRC attribute when the element is visible.
<body>
<img src="./img/default.png" data-src="./img/1.jpg" />
<img src="./img/default.png" data-src="./img/2.jpg" />
<img src="./img/default.png" data-src="./img/3.jpg" />
<img src="./img/default.png" data-src="./img/4.jpg" />
<img src="./img/default.png" data-src="./img/5.jpg" />
<img src="./img/default.png" data-src="./img/6.jpg" />
<img src="./img/default.png" data-src="./img/7.jpg" />
<img src="./img/default.png" data-src="./img/8.jpg" />
<img src="./img/default.png" data-src="./img/9.jpg" />
<img src="./img/default.png" data-src="./img/10.jpg" />
</body>
Copy the code
To obtain all the dom images, through the document. The body. The clientHeight get highly visual area, then use element. GetBoundingClientRect () directly by top value of the element relative to browse, traverse each image to judge whether the visual zone.
function lazyload() {
let viewHeight = document.body.clientHeight // Get the viewable height
let imgs = document.querySelectorAll('img[data-src]')
imgs.forEach((item, index) = > {
if (item.dataset.src === ' ') return
// Get the left, up, right, and down positions of an element on the page relative to the browser window
let rect = item.getBoundingClientRect()
if (rect.bottom >= 0 && rect.top < viewHeight) {
item.src = item.dataset.src item.removeAttribute('data-src')}}}Copy the code
Finally bind the Scroll event
window.addEventListener('scroll', lazyload)
Copy the code
This completes the lazy loading of images, but this introduces a new performance problem, as the scroll event is constantly triggered by page scrolling, so we need a “throttling” function. If you don’t know about throttling functions, check out my previous article “JavaScript” and “throttling” details and Applications.
// throttling function
function throttle(fn, delay) {
let flag = true;
return function() {
if(! flag)return;
flag = false;
setTimeout(() = > {
fn.apply(this.arguments);
flag = true;
}, delay)
}
}
Copy the code
And then you throttle the scroll
window.addEventListener('scroll', throttle(lazyload, 200))
Copy the code
And you’re done!
In vUE, we can use the custom v-lazy command to load images lazily
const LazyLoad = {
/ / install method
install(Vue,options){
// Replace the loading diagram of an image
let defaultSrc = options.default;
Vue.directive('lazy', {bind(el,binding){
LazyLoad.init(el,binding.value,defaultSrc);
},
inserted(el){
// Compatible processing
if('IntersectionObserver' in window){
LazyLoad.observe(el);
}else{ LazyLoad.listenerScroll(el); }}})},/ / initialization
init(el,val,def){
// data-src stores the true SRC
el.setAttribute('data-src',val);
// Set SRC to the loading diagram
el.setAttribute('src',def);
},
// Use IntersectionObserver to monitor EL
observe(el){
let io = new IntersectionObserver(entries= > {
let realSrc = el.dataset.src;
if(entries[0].isIntersecting){
if(realSrc){
el.src = realSrc;
el.removeAttribute('data-src'); }}}); io.observe(el); },// Listen for scroll events
listenerScroll(el){
let handler = LazyLoad.throttle(LazyLoad.load,300);
LazyLoad.load(el);
window.addEventListener('scroll'.() = > {
handler(el);
});
},
// Load the real image
load(el){
let windowHeight = document.documentElement.clientHeight
let elTop = el.getBoundingClientRect().top;
let elBtm = el.getBoundingClientRect().bottom;
let realSrc = el.dataset.src;
if(elTop - windowHeight<0&&elBtm > 0) {if(realSrc){
el.src = realSrc;
el.removeAttribute('data-src'); }}},/ / throttling
throttle(fn, delay) {
let flag = true;
return function() {
if(! flag)return;
flag = false;
setTimeout(() = > {
fn.apply(this.arguments);
flag = true;
}, delay)
}
}
export default LazyLoad;
Copy the code