场景
在网速不好时图片还没有加载出来的情况下,先展示一个默认图片做占位图(image-default.jpg),当图片加载出错时,展示加载错误图片(image-error.jpg)。
思路
在从img 元素被渲染出来到网络请求数据(这里指图片)回来是有一段时间的,而拿到图片后,图片从开始加载到加载完成也是需要一段时间的,而这个时间段的大小大多取决于你当前的宽带。
第一阶段, <img>
标签渲染出来后我们先给 src
赋值默认图片(如上图的 image-default.jpg),图片情况返回有两种情况:
第一种情况是顺利拿到图片,把拿到的图片地址赋值给 src
第二种是如果网速实在太差,请求超时,就是一直都没有拿到图片,此时 src
放的还是一开始赋值的默认图片。
第二阶段,开始加载图片,此时也有两种情况:
第一种情况是图片加载成功,
第二种是图片地址无效,加载失败,此时 src
放的还是一开始赋值的默认图片,这种情况下你可以不做处理,或者把 src
赋值为一张加载错误图片(如上图的 image-error.jpg)。怎么判断图片是否能加载成功?可以先自己创建一个图片对象 Image
,Image 对象有两个方法,图片加载完成时触发的 image.onload
事件,和图片加载错误时触发的 image.onerror
事件。在这个两个事件中我们可以对页面上一开始就渲染出来的 <img>
标签做相应的处理。
具体实现:
功能预想:
把上面的思路套在 vue 指令上。给 img
标签添加指令 v-image
来实现图片预加载,其中预加载图片可不传(有默认值),图片加载错误时占位图可不传(有默认值)。
用法:
<img class="cover" v-image="cover">
// or
<img class="cover" v-image="cover" :default-img="" :error-img="">
``
其中 default-img 和 error-img 可选,cover 是请求回来真正要展示的图片,必传。
在下面的实现方法里,占位图有三种,
一种是 “系统默认占位图”,即如果直接 <img v-image="cover">
使用,指令内会默认加载一张占位图。那么图片未加载完时或者加载错误时用的都是这张图片
一种是 “指定默认占位图”,用法 <img v-image="cover" :default-img="">
那么图片未加载完时用的是这张图片。
一种是 “指定加载错误占位图” ,用法 <img v-image="cover" :error-img="">
那么图片加载错误时用的是这张图片。
具体实现代码:
/**
* @description
* @param {string} v-image (yes) 图片地址
* @param {string} default-img (no) 预加载占位图
* @param {string} error-img (no) 加载错误占位图
* @example
* <img v-image="cover" :default-img="" :error-img="">
*/
/**
* @description 检测图片地址是否有效
* @param url
*/
const imageIsExist = function(url) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = function() { // 图片地址有效
if (this.complete === true) {
resolve(image)
}
}
image.onerror = function() { // 图片加载失败
reject('could not load image')
}
image.src = url
})
}
export default function(el, binding) {
let placeholderImage = require('@/common/images/image-default.jpg') // 默认占位图
let defaultImage = el.getAttribute('default-img') // 外部传入的默认占位图
let errorImage = el.getAttribute('error-img') // 外部传入的错误占位图
el.setAttribute('src', defaultImage || placeholderImage)
// el.setAttribute('class', 'img-objectfix-contain')
let realImageUrl = binding.value // 获取图片地址( v-image="cover" 的 cover)
if (realImageUrl) {
imageIsExist(realImageUrl)
.then(() => {
el.setAttribute('src', realImageUrl)
})
.catch(() => {
el.setAttribute('src', errorImage || placeholderImage)
})
}
}
参考