Lazy loading instructions for custom images in Vue2 2.0
Since the custom image lazy loading instruction data in Vue2 I shared the day before yesterday is very good, so I will continue to share the second implementation method here - use Intersection Observer API
.
This method is simpler to implement and use, and has better performance. The only disadvantage is that the compatibility is not so good, but it is basically compatible with most browsers on the market (except IE). I believe that the compatibility will definitely be better in the future. The better it is, so everyone can learn it in advance.
Friends who are not familiar with the API can go to my blog explaining the Intersection Observer API in vernacular .
Friends who haven’t seen the lazy loading instruction blog of custom images in Vue2 that I shared the day before yesterday , I strongly recommend you to check it out.
2. Basic introduction to image lazy loading instructions
2.1 The final realization effect
The final effect is as follows:
2.2 Registration and use of image lazy loading instructions
Since the image lazy loading instruction is frequently used in the personal blog system, I still choose to register this instruction globally.
Because Intersection Observer API
internally and asynchronously detect changes in the intersection of the target element and the root element . So we no longer need to use the event bus for communication, so there is no need to introduce the event bus configuration file.
main.js入口文件
The code is as follows:
import Vue from "vue";
import App from "./App.vue";
import vLazy from "./directives/lazy";
Vue.directive("lazy", vLazy); //全局注册指令
new Vue({
render: (h) => h(App),
}).$mount("#app");
Since there is no event bus for communication, it is extremely convenient to use, just bind the src attribute of the img image element to the v-lazy custom instruction .
So v-lazy 指令
the sample code is as follows:
<template>
<div class="container">
<ul>
<li v-for="img in imgs" :key="img.id">
<img v-lazy="img.src" :alt="img.alt" :title="img.title" />
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
imgs: [
{
id: "",
src: "",
alt: "",
title: "",
},
],
};
},
};
</script>
2. The principle of lazy loading of images
Friends Intersection Observer API
who are not familiar with it can go to my blog explaining the Intersection Observer API in detail . (Writing this blog took a lot of thought and drew a lot of pictures)
2.1 Comparison with the realization principle of the previous blog
In the last blog, I raised the following four questions and answered them, summarized as follows:
- How to monitor the scrolling of the container's scroll bar?
- At that time, we used
事件总线
the method to listen to the wheel event of the parent container element, and used事件防抖
the tool function for performance optimization.
- At that time, we used
- Which hook functions to use custom directives?
- At that time, we used
inserted
theseunbind
two hook functions and used the imgs array to collect the DOM and src information of img.
- At that time, we used
- How to judge whether the image img element is within the visible range of the user?
- At that time, we used
Element.clientWidth
andElement.getBoundingClientRect()
these two APIs, and made a logical judgment on the information obtained by the APIs.
- At that time, we used
- How to handle loading of image img element?
- At that time, we used
Image 对象实例
instead of the img target element to load the image, and rewrittenImage 对象
itonload事件
, and performed the src attribute replacement operation of the img target element inside.
- At that time, we used
In the previous blog, the solutions to problems 2 and 4 have hardly changed, while problems 1 and 3 can be solved directly and easily Intersection Observer API
, as follows:
- How to monitor the scrolling of the container's scroll bar?
- We just need
IntersectionObserver对像
to set the root element of the viewport. (Do not pass root attribute and threshold attribute)
- We just need
- Which hook functions to use custom directives?
- At that time, we used
inserted
theseunbind
two hook functions and used the imgsInf array to collect the DOM and src information of img. (no change, only variable name changes)
- At that time, we used
- How to judge whether the image img element is within the visible range of the user?
- We only need to use the
IntersectionObserverEntry对象
attributesisIntersecting
to judge.
- We only need to use the
- How to handle loading of image img element?
- At that time, we used
Image 对象实例
instead of the img target element to load the image, and rewrittenImage 对象
itonload事件
, and performed the src attribute replacement operation of the img target element inside. (No change, just function encapsulation)
- At that time, we used
See the table below for a detailed comparison of the two blogs:
The solution of the previous blog | The solution in this blog | |
---|---|---|
How to monitor the scrolling of the container's scroll bar? | Event bus + function anti-shake | set IntersectionObserver对像 as root属性 the viewport |
Which hook functions to use custom directives? | inserted + unbind | Consistent with the previous blog, only the variable name has been changed |
How to judge whether the image img element is within the visible range of the user? | clientWidth + getBoundingClientRect() | IntersectionObserverEntry对象 ofisIntersecting属性 |
How to handle loading of image img element? | Use an Image object instance instead of loading | Consistent with the previous blog, only function encapsulation |
It seems that the implementation of the method that everyone should know Intersection Observer API
is simpler.
2.2 Implementation steps
- Let's write the code to solve problem 2 and problem 4 directly:
import defaultGif from "@/assets/default.gif"; //在assets静态文件夹下放入默认图
let imgsInf = []; //存储尚未加载的图片信息
//调用该函数 用于加载单张图片
function loadingImg(imgDOM) {
//获得该img元素的src信息
let imgSrc = imgsInf.filter((imgInf) => imgInf.dom === imgDOM)[0].src;
const tempImg = new Image(); //新建Image对象实例
//改写onload事件
tempImg.onload = function () {
// 当图片加载完成之后 替换img元素的src属性
imgDOM.src = imgSrc;
};
tempImg.src = imgSrc; //Image实例代替加载
imgsInf = imgsInf.filter((imgInf) => imgInf.dom !== imgDOM); //将已加载好的图片进行删除
}
export default {
inserted(el, bindings) {
//刚插入父节点时
el.src = defaultGif; // 先暂时使用默认图片的src
const imgInf = {
dom: el, //img 元素DOM节点
src: bindings.value, //img的真正src信息
};
imgsInf.push(imgInf); //存储img元素的src信息
},
unbind(el) {
//解绑时 清空 imgs
imgsInf = imgsInf.filter((imgInf) => imgInf.dom !== el);
},
};
- Create
IntersectionObserver对象
and configure accordingly, the code is as follows:
//io 为 IntersectionObserver对象 - 由IntersectionObserver()构造器创建
const io = new IntersectionObserver((entries) => {
//entries 为 IntersectionObserverEntry对像数组
entries.forEach((item) => {
//item为 IntersectionObserverEntry 对象
// isIntersecting是一个Boolean值,判断目标元素当前是否可见
if (item.isIntersecting) {
//img元素可见时
loadingImg(item.target); //加载该img元素
io.unobserve(item.target); //图片加载完后即停止监听该元素
}
});
}); //不传options参数
//默认根元素(root属性)为浏览器视口、
//默认阈值(threshold属性)为 0,表示目标元素刚进入根元素可见范围时触发回调函数
- The start listening method and the stop listening method are used at the appropriate position, so the overall code is as
IntersectionObserver对象
follows :observe
unobserve
import defaultGif from "@/assets/default.gif"; //在assets静态文件夹下放入默认图
let imgsInf = []; //存储尚未加载的图片信息
//调用该函数 用于加载单张图片
function loadingImg(imgDOM) {
//获得该img元素的src信息
let imgSrc = imgsInf.filter((imgInf) => imgInf.dom === imgDOM)[0].src;
const tempImg = new Image(); //新建Image对象实例
//改写onload事件
tempImg.onload = function () {
// 当图片加载完成之后 替换img元素的src属性
imgDOM.src = imgSrc;
};
tempImg.src = imgSrc; //Image实例代替加载
imgsInf = imgsInf.filter((imgInf) => imgInf.dom !== imgDOM); //将已加载好的图片进行删除
}
//io 为 IntersectionObserver对象 - 由IntersectionObserver()构造器创建
const io = new IntersectionObserver((entries) => {
//entries 为 IntersectionObserverEntry对像数组
entries.forEach((item) => {
//item为 IntersectionObserverEntry 对象
// isIntersecting是一个Boolean值,判断目标元素当前是否可见
if (item.isIntersecting) {
//img元素可见时
loadingImg(item.target); //加载该img元素
io.unobserve(item.target); //图片加载完后即停止监听该元素
}
});
}); //不传options参数
//默认根元素(root属性)为浏览器视口、
//默认阈值(threshold属性)为 0,表示目标元素刚进入根元素可见范围时触发回调函数
export default {
inserted(el, bindings) {
//刚插入父节点时
el.src = defaultGif; // 先暂时使用默认图片的src
io.observe(el); //开始监听该img元素
const imgInf = {
dom: el, //img 元素DOM节点
src: bindings.value, //img的真正src信息
};
imgsInf.push(imgInf); //存储img元素的src信息
},
unbind(el) {
//某个img元素解绑时 清除该img元素的信息 并停止监听该img元素
io.unobserve(el); //停止监听
imgsInf = imgsInf.filter((imgInf) => imgInf.dom !== el); //清除存储信息
},
};
The logical judgment of this method is much simpler than the method in the previous blog, so learning it will definitely bring convenience to our development.
3. Intersection Observer API Compatibility
Intersection Observer API
The compatibility is as follows:
[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-l7VE7frt-1663962746438)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp /562af71865f84020be86acefe260b263~tplv-k3u1fbpfcp-watermark.image?)]
You can choose to use it in actual projects.
For details, please refer to CAN I USE - intersectionobserver .
reference blog
- Explain the Intersection Observer API in plain language
- Lazy loading instructions for custom images in Vue2
epilogue
This is the best answer in the knowledge I know so far, and of course there may be some misunderstandings.
So if you have doubts about this article, you can leave a message in the comment area, and I will reply in time. You are welcome to point out the wrong views in the article.
In the end, the code words are not easy, and friends who find it helpful will like, bookmark, and follow along.