图片加载存在的问题和原因
- 问题一:启动页面时加载过多图片
- 问题二:部分图片体积过大
解决方案
- 针对第一个问题解决方案
在 Vue 指令中包含两个钩子函数 bind 和 inserted。
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
判断哪些是首屏图片,通过使用 v-img 指令的时候,传 defer 配置项来告诉 v-img 哪些图片需要提前加载,哪些图片等待提前加载的图片加载完毕后再加载。这样我们就能够在 bind 钩子函数中加载优先加载的图片了。
<img v-img="{ hash: 'xxx', defer: true }">
const promises = [] // 用来存储优先加载的图片
Vue.directive('img', {
bind(el, binding, vnode) {
// ...
const { defer } = binding.value
// ...
if (!defer) {
promises.push(update(el, binding, vnode))
}
},
inserted(el, binding, vnode) {
const { defer } = binding.value
if (!defer) return
if (inViewport(el)) {
promises.push(update(el, binding, vnode))
} else {
Vue.nextTick(() => {
Promise.all(promises)
.then(() => {
promises.length = 0
update(el, binding, vnode)
})
.catch(() => {})
})
}
},
// ...
})
解析: 首先通过声明一个数组 promises 用于存储优先加载的图片,在 bind 钩子函数内部,如果 defer 配置项为 false,说明不延时加载,那么就在 bind 钩子函数内部加载该图片,且将返回的 promise 推入到 promises 数组中。在 inserted 钩子函数内,对于延迟加载的图片(defer 为 true),但是其又在首屏内,那么也有优先加载权,在 inseted 钩子函数调用时就对其加载。而对于非首屏且延迟加载的图片等待 promises 数组内部所有的图片都加载完成后才加载
- 针对第二个问题解决方案
图片体积过大,导致下载时间过长。在保证清晰度的前提下尽量使用体积较小的图片。而一张图片的体积由两个因素决定,该图片总的像素数目和编码单位像素所需的字节数。因此一张图片的文件大小就等于图片总像素数目乘以编码单位像素所需字节数。
使用的 lib-flexible 来对不同的移动端设备进行适配,lib-flexible 库在我们页面的html元素添加了两个属性,data-dpr 和 style。这儿我们主要会用到 style 中的 font-size 值,在一定的设备范围内其正好是html元素宽度的十分之一