关于vue.js:自定义指令实现渐进加载图片

3次阅读

共计 1800 个字符,预计需要花费 5 分钟才能阅读完成。

开发背景

咱们网站内的所有图片都是从上到下扫描渲染的,如果网速较慢的时候,图片由 0 到 1 的整个过程将会呈现较长的耗时,且留有较长的空白工夫,针对这一问题,起初我的做法通常都是应用一张占位图,然而实在图片替换占位图的过程会呈现闪动的景象,于是我应用了渐进加载图片的形式对我的项目进行了优化。

渐进加载的整体流程?

页面中的图片能够先加载一个图片的含糊轮廓(小图),随着图片加载时长的减少,图片会逐步变得清晰。
这里咱们须要留神几个问题:

  • 如何使用户无感知的替换新老图片?
  • 如果页面内须要渲染多个图片,那咱们岂不是要多增加 n 个 DOM?

    理论开发

    咱们我的项目中图片均是通过 oss 存储的,所以小图能够通 url+ 参数的模式获取。例如,http://image-demo.oss-cn-hang…,h_100,m_lfit。如果应用的是别的链接均可自行替换

  • 增加自定义指令,因为我的项目中多个中央均需应用,所以采纳的是全局增加的模式。

    import Vue from 'vue'
    const gradual = Vue.directive('gradual', {bind(el, binding) {instertDom(el, binding)
    },
    })
    export default gradual
  • 我的项目中所有须要用到渐进加载的图片咱们均能够先用小图替换。实在图片咱们能够通过指令传值的模式发送进来。

    <img 
    v-gradual="{src: $img + item.extend.titleImg}"
    :src="$img + item.extend.titleImg +'?x-oss-process=image/resize,l_50'"alt=""
    />

    加载大小图片的比照

  1. 新图片的增加及含糊图片的替换

    • 之前提到的问题一咱们能够通过透明度由 1 变 0 的过渡成果,对含糊图片进行暗藏,其中应用的 filter:blur() 是为了保障含糊图片的像素化不会那么显著。
    • 针对问题二,采纳的是 img 标签的 onload 事件,在判断大图加载实现后,先对原有 DOM 增加暗藏成果,而后通过设置定时器的形式删除原有 DOM,这里的定时器 delay 要大于等于过渡动画中的delay,以保障过渡成果全副显示实现。

css 局部

  .gradual .vague{filter: blur(2px);
  }

  .gradual img.gradual-hide_img {
    opacity: 0;
    animation: origin 1s ease;
  }
  
  .gradual img.gradual-hide_img {
    position: absolute;
    left: 0;
    top: 0;
  }
  
  @keyframes origin {
    0% {transform: scale(1);
      opacity: 1;
    }
    100% {transform: scale(1.1);
      opacity: 0;
    }
  }

js 局部

const instertDom = (target, binding) => {Vue.nextTick(() => {
    const parent = target.parentNode
    parent.classList.add('gradual')
    target.classList.add('vague')
    const newElement = document.createElement('img')
    newElement.classList.add('origin')
    // 要先写 onload 再增加 src
    newElement.onload = () => {target.classList.add('gradual-hide_img')
      // 删除原 DOM 定时器能够多设置点
      setTimeout(() => {target.remove()
      }, 1500)
    }
    newElement.src = binding.value.src
    if (parent.lastChild === target) {parent.appendChild(newElement)
    } else {parent.insertBefore(newElement, target.nextSibling)
    }
  })
}

ps:Vue.nextTick()是肯定要带的,以保障页面 DOM 全副加载实现。不然页面中的 target.parentNode 会是null

总结

渐进加载的整体流程能够归纳如下:

加载小图 -> 渲染 -> 加载大图 -> 判断大图加载实现 -> 小图增加隐没过渡 -> 删除小图 DOM。

正文完
 0