开发背景
咱们网站内的所有图片都是从上到下扫描渲染的,如果网速较慢的时候,图片由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变0的过渡成果,对含糊图片进行暗藏,其中应用的
filter:blur()
是为了保障含糊图片的像素化不会那么显著。 - 针对问题二,采纳的是
img
标签的onload
事件,在判断大图加载实现后,先对原有DOM增加暗藏成果,而后通过设置定时器的形式删除原有DOM,这里的定时器delay
要大于等于过渡动画中的delay
,以保障过渡成果全副显示实现。
- 之前提到的问题一咱们能够通过透明度由1变0的过渡成果,对含糊图片进行暗藏,其中应用的
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。