vue 图片懒加载

43 阅读2分钟

效果

文章列表的图片懒加载, 只要图片位于视口位置就会加载图片, 否则显示默认图片

动画.gif

实现

1. 使用指令进行懒加载

如果为图片设置src,浏览器会自动地获取图片,使用指令给图片加一层处理

// 创建一个v-lazy的指令, 图片就可以使用它实现懒加载
import vLazy from "./directives/lazy";
Vue.directive("lazy", vLazy);

2. 使用指令周期钩子函数对数据处理

// 到处两个钩子对象
// 当被绑定元素插入父节点时使用,记录dom 和真实的src
export default {
  inserted: function(el, binding) {
    const img = {
      dom: el,
      src: binding.value,
    };
    imgs.push(img);
    setImage(img);
  },
  
  // 当元素解绑时处理记录的imgs,清空
  unbind: function(el) {
    //  img.dom ===el 是等于的,会返回true,但是unbind要清除狗子函数,所有要!==
    imgs = imgs.filter((img) => img.dom !== el);
  },
};

3. 单个img的视口边界判定setImage(img)

为一个函数,接受一个img对象, 判断是否位于视口,是的话就加载图片

function setImage(img) {
  // 统统设置为默认图片
  img.dom.src = defaultGif;

  const clientHeight = document.documentElement.clientHeight;
  const rect = img.dom.getBoundingClientRect();
  const height = rect.height || 150;
  //rect.top>=-height 是用来判断是否部分在视口范围内的
  if (rect.top >= -height && rect.top <= clientHeight) {
    const tempImg = new Image();
    tempImg.onload = () => {
      img.dom.src = img.src;
      // 图片加载完成对imgs处理,已处理的清除掉
      imgs = imgs.filter((i) => i !== img);
    };
    tempImg.src = img.src;
  }
}

4. 事件总线处理scroll 懒加载

步骤3的 setImage 对单个img 的懒加载处理, 事件总线监听scroll触发懒加载

// 防抖处理
eventBus.$bus.$on("mainScroll", debounce(handleScroll, 50));

function handleScroll() {
  setImages();
}
//循环所有img进行懒加载处理
function setImages() {
  for (const img of imgs) {
    setImage(img);
  }
}

感想

  1. 数据分为已处理和未处理时,直接将已处理的数据从这个数据里删除
  2. 数据每次获取了, 如果重新加载又会重新获取需要清理操作,清除之前的数据