?对于vue项目而言,图片懒加载是一个常见的图片加载方案,可以优化用户体验,而vue-lazyload则是一个广泛使用的插件。
?对于某些业务场景,我们需要
业务场景
试想这样的场景:
在img标签上,使用v-lazy绑定的图片的地址。
图片的地址可能有误 ,图片可能因此加载失败。这时,我们需要重新给图片赋予新的正确地址,使图片加载出来。应该如何处理?
你可能持有怀疑,为什么图片地址会不正确呢?事实上,对某些技术架构而言,的确有可能,例如:
图片的源文件非常大,可能达到几十M,这时我们不会加载源文件地址,而是加载缩略图,缩略图的体积大大减小,利于我们提升用户体验,缩小等待时间。然而,缩略图是由阿里云oss提供的服务,它会自动为我们进行图片裁剪,得到缩略图,不过源文件限制在20M以内。这样,当我们加载缩略图时,如果源文件的尺寸大于20M,缩略图就不会存在,使得图片加载失败,这时我们需要加载源文件地址。
当上述情况发生时,我们就需要监听v-lazyload的图片加载失败事件,重新请求源文件地址了。
常见解决方案分析
1.使用filter选项,修改源文件地址
在官方文档中,做了示例,可以通过filter选项修改图片地址。问题在于,该方案无法检测图片源文件的尺寸,也无法判断指定图片地址是否存在。如果要通过请求探测指定地址的图片是否存在,则会使得加载时间大大加长,不利于用户体验。并且针对全局生效,很难针对各种情况做合理配置。
2.使用adapter选项,监听error事件
我们可以通过adapter的error选项,监听到图片加载失败。但是
3.使用vm.$Lazyload.$on 或vm.$Lazyload.$once 监听error事件
对于这两个选项而言,我们可以在vue的组件实例中,通过
然而,经笔者实测,这两个事件虽然会触发,然而
(当然,不排除笔者没有领会设计者意图的可能,如果你使用这两个事件成功了,请告知。)
推荐解决方案:dispatchEvent + @error
我们只需要做两个地方的处理,就能达到预期。首先是对vue-lazyload做全局配置,开启dispatchEvent选项:
1 2 3 4 5 6 | Vue.use(VueLazyload, { loading: require("@/assets/images/lazy-loading.svg"), error: require("@/assets/images/lazy-loading.svg"), dispatchEvent: true, attempt: 1 }); |
在以上情况下,我们将dispatchEvent设置为true,表明开启img的原生dom事件,默认情况下,该选项是false,是不会开启原生dom事件的。这样,我们现在可以监听img的原生error事件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | <template> <div class="card"> <div class="card-img"> <img v-lazy="thumbImgUrl" alt="" @click="onPreview" v-if="showThumb" @error="handleLazyErr" /> <img v-lazy="data.imgUrl" alt="" @click="onPreview" v-else /> <el-image-viewer v-if="showViewer" :on-close="closeViewer" :url-list="[previewImgUrl]" /> </div> <div class="card-name">{{ data.name }}</div> </div> </template> <script> import ElImageViewer from "element-ui/packages/image/src/image-viewer"; export default { name: "", components: { ElImageViewer }, props: { data: { type: Object, default() { return {}; } } }, data() { return { showThumb: true, showViewer: false }; }, methods: { onPreview() { this.showViewer = true; }, // 关闭查看器 closeViewer() { this.showViewer = false; }, // 监听加载失败 handleLazyErr() { setTimeout(() => { this.showThumb = false; }, 2000); } }, computed: { // 原图太大,显示缩略图 thumbImgUrl() { return `${this.data.imgUrl}?x-oss-process=image/resize,h_355,w_268`; }, previewImgUrl() { let url; if (this.showThumb) { url = `${this.data.imgUrl}?x-oss-process=image/resize,w_1920`; } else { url = this.data.imgUrl; } return url; } } }; </script> |
现在,在以上案例中,我们通过监听到图片加载失败触发原生的error事件,来加载图片源文件,这样就比较巧妙的实现了失败时显示原图的需求。
本文完。