Lazy loading instructions for custom images in Vue2 2.0

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:
insert image description here

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 APIinternally 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 APIwho 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:

  1. 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.
  2. Which hook functions to use custom directives?
    • At that time, we used insertedthese unbindtwo hook functions and used the imgs array to collect the DOM and src information of img.
  3. How to judge whether the image img element is within the visible range of the user?
    • At that time, we used Element.clientWidthand Element.getBoundingClientRect()these two APIs, and made a logical judgment on the information obtained by the APIs.
  4. 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 rewritten Image 对象it onload事件, and performed the src attribute replacement operation of the img target element inside.

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:

  1. 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)
  2. Which hook functions to use custom directives?
    • At that time, we used insertedthese unbindtwo hook functions and used the imgsInf array to collect the DOM and src information of img. (no change, only variable name changes)
  3. How to judge whether the image img element is within the visible range of the user?
    • We only need to use the IntersectionObserverEntry对象attributes isIntersectingto judge.
  4. 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 rewritten Image 对象it onload事件, and performed the src attribute replacement operation of the img target element inside. (No change, just function encapsulation)

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 APIis simpler.

2.2 Implementation steps

  1. 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);
  },
};
  1. 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,表示目标元素刚进入根元素可见范围时触发回调函数
  1. The start listening method and the stop listening method are used at the appropriate position, so the overall code is as IntersectionObserver对象follows :observeunobserve
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 APIThe 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

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.

Guess you like

Origin blog.csdn.net/forward_xx/article/details/127020639