Напишите инструкцию ленивой загрузки изображения Vue в 30 строк

Vue.js

предисловие

Хорошо, братья. В предыдущей статье говорилось, что ленивую загрузку изображений нужно реализовать в виде инструкций. На самом деле, после стольких лет фронтенд-разработки реализовать ленивую загрузку изображений очень просто.С помощью инструкций Vue 30 строк легко реализуют многократно используемую инструкцию Vue. Давайте посмотрим вместе.

v-imgLazy

Здесь я использую IntersectionObserver API для его реализации.

МетодObserver() объекта IntersectionObserver добавляет в целевую коллекцию элемент, прослушиваемый объектом IntersectionObserver. Слушатель имеет набор пороговых значений и корень, но может отслеживать несколько целевых элементов, чтобы видеть изменения в видимой области этих целевых элементов.

Проще говоря, вы можете отслеживать вход и выход элементов DOM в видимую область и из нее, а также контролировать определенные изменения.

Пожалуйста, смотрите конкретное использованиеIntersectionObserver API

Создайте новую директиву для хранения пользовательских директив

directive/imgLazy.js

// 引入默认图片
import baseImg from '@/assets/logo.png';

let timer = null;
// 创建一个监听器
let observer = new IntersectionObserver((entries)=>{
  // entries是所有被监听对象的集合
  entries.forEach(entry =>{
    if(entry.isIntersecting || entry.intersectionRatio>0){
      // 当被监听元素到临界值且未加载图片时触发。
      !entry.target.isLoaded  && showImage(entry.target,entry.target.data_src)
    }
  })
})
function showImage(el,imgSrc){
  const img = new Image();
  img.src = imgSrc;
  img.onload = ()=>{
    el.src = imgSrc;
    el.isLoaded = true;
  }
}
export default {
  // 这里用inserted和bind都行,因为IntersectionObserver时异步的,以防意外还是用inserted好一点
  // inserted和bind的区别在于inserted时元素已经插入页面,能够直接获取到dom元素的位置信息。
  inserted(el,binding,vnode) {
    clearTimeout(timer)
    // 初始化时展示默认图片
    el.src = baseImg;
    // 将需要加载的图片地址绑定在dom上
    el.data_src = binding.value;
    observer.observe(el)

    // 防抖,这里在组件卸载的时候停止监听
    const vm = vnode.context;
    timer = setTimeout(() => {
      vm.$on('hook:beforeDestroy', () => {
        observer.disconnect();
      })
    }, 20);
  },
  // 图片更新触发
  update(el,binding){
    el.isLoaded = false;
    el.data_src = binding.value;
  },
  // unbind不太好,会执行多次,改进一下用组件的beforeDestroy卸载
  // unbind(){
  //   // 停止监听
  //   observer.disconnect();
  // }
}

Использовать в main.js, зарегистрировать глобальную директиву

main.js

import imgLazy from '@/directive/imgLazy.js'
Vue.directive('imgLazy', imgLazy)

Определите директивы в используемом компоненте, зарегистрируйте директиву для текущего компонента

import imgLazy from '@/directive/imgLazy.js'
export default {
  // ...
  directives: {
    imgLazy: imgLazy,
  },
}

используемые компоненты

<template>
  <div class='container'>
    <div v-for="(item,index) in imgSrc" :key="index" >
      <img v-imgLazy="item" >
    </div>
  </div>
</template>

<script>
import imgLazy from '@/directive/imgLazy.js'
export default {
  directives: {
    imgLazy: imgLazy,
  },
  data(){
    return {
      imgSrc:[
        "https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1091405991,859863778&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2396395246,715775841&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=224866248,765861809&fm=26&gp=0.jpg",
        "https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2670715487,1547868437&fm=26&gp=0.jpg",
        "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2988957523,3295751190&fm=26&gp=0.jpg",
        "https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2698110318,782174384&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1102788601,953675482&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1091405991,859863778&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2396395246,715775841&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=224866248,765861809&fm=26&gp=0.jpg",
        "https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2670715487,1547868437&fm=26&gp=0.jpg",
        "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2988957523,3295751190&fm=26&gp=0.jpg",
        "https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2698110318,782174384&fm=26&gp=0.jpg",
        "https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1102788601,953675482&fm=26&gp=0.jpg",
        "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2004055534,3969071219&fm=26&gp=0.jpg",
      ]
    }
  }
}
</script>

<style lang="scss" scoped>
img{
  width: 200px;
  height: 200px;
}
</style>

Конкретные эффекты следующие:

Совместимость IntersectionObserver

Совместимость API IntersectionObserver в основном совместима, за исключением IE, поэтому, если вы хотите реализовать ленивую загрузку в IE, вы можете только самостоятельно вычислить каждый элемент. Когда я представил миксин в предыдущей статье, я написал о ленивой загрузке, которая может служить ссылкой.

ад IE

Прошлые статьи:

Научит вас, как использовать инструкции Vue и реализовать инструкции маркера новостей и анимации движения вручную.

Что вы знаете о миксинах Vue? Как использовать миксин для реализации функции ленивой загрузки изображений

Приведенный выше код был объединен врепозиторий gitee