Skip to content
大纲

图片懒加载

在实现图片懒加载时, 除了可以某一条件触发后再请求图片接口外, 图片本身的渲染也可以进行懒加载。

分析

例如这样一个场景, 网页下拉至底部请求回来十个图片 URL 路径, 甚至更多。如果未作任何处理, 那么用户在页面上暂时看不到的一些图片也会进行资源请求, 对于视口上的图片来说无疑是抢占了他们一些资源, 导致加载速度慢。

我们可以尝试做这样的一层优化, 处于视口的图片才进行资源请求, 否则, 以一些颜色背景替代。

不过这样有一个前提, 就是除了返回图片 URL 外, 还必须知晓渲染图片的宽高。

想要实现它的逻辑也非常简单, 只需判断图片是否可见:

  • 不可见 src 为空, 填充颜色
  • 可见 src 赋值为图片 URL 路径

自定义指令形式实现

对于这样的一个场景, 最好的实现方式是通过自定义指令的形式, 例如 v-lazy。这样可以方便的控制哪些图片需要懒加载, 哪些提前渲染好一些。

js
import { useIntersectionObserver } from '@vueuse/core'

export default {
  // 图片懒加载:在用户无法看到图片时,不加载图片,在用户可以看到图片后加载图片
  // 如何做到不加载图片(网络):img 标签渲染图片,指的是 img 的 src 属性,src 属性是网络地址时,则会从网络中获取该图片资源。
  // 那么如果 img 标签不是网络地址呢?把该网络地址默认替换为非网络地址,然后当用户可见时,在替换成网络地址。

  mounted(el, binding) {
    // 但是有一个前提, 必须要含有宽高才能懒加载, 也就是不能人为计算宽高
    // 这里可进一步控制 v-lazy="" 的值为什么时候才需懒加载
    if (binding.value) return
    // 1. 拿到当前 img 标签的 src
    const imgSrc = el.src
    // 2. 把 img 标签的 src 替换为本地地址
    el.src = ''
    const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
      if (isIntersecting) {
        // 3. 替换地址
        el.src = imgSrc
        // 4. 停止监听
        stop()
      }
    })
  },
}

插件形式安装

在实现了 v-lazy 自定义指令后, 由于实际项目中的自定义插件可能并不止这一个, 可以通过插件的形式进行安装。

js
export default {
  install(app) {
    // import.meta.globEager 为同步导入
    // const directives = import.meta.globEager('./*.js') // globEager 已弃用
    const directives = import.meta.glob('./*.js', { eager: true })
    console.log('directives', directives)
    for (const [key, value] of Object.entries(directives)) {
      // 拼接组件注册的 name
      console.log(key, value)
      const arr = key.split('/')
      const directiveName = arr[arr.length - 1].replace('.js', '')
      // 完成注册
      app.directive(directiveName, value.default)
    }
  },
}

Mochi's personal blog.