结合事件总线的Vue自定义图片懒加载效果

92 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

图片懒加载效果

自定义了一个指令 Lazy

主要思想,图片如何加载当然要涉及,监听页面的滚动(事件总线),当图片这个元素的位置,在视口区域中的时候加载真实图片; 当没有在视口范围内时,就默认一个图片。

  1. 用自定义事件中的钩子函数,当自定义指令与元素绑定的时候,获取元素,以及 binging 对象。然后以对象的形式存储在一个数组中
  2. 这个数组,当我们切换页面的时候由于 Lazy 绑定了新的 img,你们数组就会在之前的基础上增加,也就是上一页的数据依然存在,然而我们不应该加载上一页的数据,所以我们就想到了用钩子函数unbind()当元素与指令解绑也就是元素销毁时(那么显然就是不存在与当前页面中),将其在数组中去掉
  3. 要判断图片需不需要加载就是需要循环数组,获取其中对象的距离视口的值,在一定区域内的图片就需要加载,将处理完成的 dom 去除。最后,这里new Image()是因为 Image 实例中有 onload 事件,在真实的图片加载完成时触发,将恢复真实的图片,
// 导入事件总线
import eventBus from "@/eventBus.js";
// 做一个防抖
import { debounce } from "@/utils";
import defaultGif from "@/assets/default.gif";
// 用一个数组来存储dom
let imgs = [];

function setImage(img) {
  // 处理图片,
  img.dom.src = defaultGif; //全部用默认的图片
  //看dom是否在一定区域之内
  //   视口高度
  const clientHeight = document.documentElement.clientHeight;
  const range = img.dom.getBoundingClientRect();
  const height = range.top || 100;
  if (range.top >= -height || range.top < clientHeight) {
    // 在视口范围
    const tempImage = new Image();
    tempImage.onload = function () {
      // 当真实图片加载完成后
      img.dom.src = img.src;
    };
    tempImage.src = img.src;
    // 加载完成就在数组中移除
    imgs.filter((i) => {
      return i !== img;
    });
  }
}
// 再监听到页面的滚动事件,调用该函数来加载应该显示的图片
function setImages() {
  // 循环数组找到当中符合一定区域内的dom,
  for (const img of imgs) {
    setImage(img);
  }
  console.log("senf");
}

function handleScroll() {
  setImages();
}

// 监听事件,并且对事件监听到了之后作出处理
eventBus.$on("mainScroll", debounce(handleScroll, 250));

export default {
  inserted(el, bingding) {
    const img = {
      dom: el,
      src: bingding.value,
    };
    imgs.push(img);
    // 这里用来处理,一开始还没有滚动事件发生的时候,
    // 就需要对图片做一个处理
    setImage(img);
  },
  unbind(el) {
    // 当指令与元素解绑也就是元素消失的时候,讲数组中不等于解绑元素的dom保留,解绑了就去掉
    imgs = imgs.filter((img) => {
      return img.dom != el;
    });
  },
};