v-viewer简介
v-viewer 是一个 Vue 组件,用于显示图片和其他媒体内容的全屏查看器。它基于 Viewer.js,一个强大的图片查看库。
以下是一个基本的使用示例:
<template><div v-viewer><img src="image1.jpg" /><img src="image2.jpg" /><img src="image3.jpg" /></div>
</template><script>
import Viewer from 'v-viewer'
import 'viewerjs/dist/viewer.css'export default {name: 'MyComponent',directives: {viewer: Viewer},data() {return {viewerOptions: {inline: false,button: true,navbar: true,title: true,toolbar: true,tooltip: true,movable: true,zoomable: true,rotatable: true,scalable: true,transition: true,fullscreen: true,keyboard: true,url: 'data-source'}}}
}
</script>
在这个示例中,我们导入了 v-viewer 和相关的 CSS,然后在模板中使用 v-viewer 指令。每个 img 元素都会自动成为查看器的目标。
v-viewer 提供了许多选项,如 inline、button、navbar、title、toolbar 等,用于自定义查看器的行为和外观。你可以在 viewerOptions 对象中设置这些选项。
更多详细的信息,你可以查看 v-viewer 的 GitHub 页面。
问题及解决方案
改插件能够很方方便的用来进行图片的预览,放大缩小等各种操作。然而,在实际使用中,有用户反馈图片加载很慢的问题,希望能对此进行优化。
图片尺寸大
针对此种情况,我们首先针对用户反应的情况进行了排查,发现用户上传的图片很大,一般在5-7M左右。这种情况通常发生在用户手机端上传,由于现代手机都具有较高的拍照像素,所以通常而言图片会很大。
于是,首先我们对图片进行了压缩上传,尽可能降低图片的大小,用以提升用户预览体验。
多次重复加载
在上面进行了压缩上传以后,一段时间后,用户还是反馈图片预览慢。此时我们就排查了下预览时,前端的网络请求耗时等,发现v-viewer在对同一张图片预览时,加载了3次,直到3次下载完成后,图片预览才算完成。这就相当于用时是正常预期的3倍。
这里就需要查看dom,看看为什么加载了3次。dom结构如下
这3处dom都包含了同一图片,分别为渲染前的原始dom节点,v-viewer渲染的大图预览,以及隐藏的小图navbar。由此可以看到,即便我们没有启用小图索引,dom结构中依然有,只是隐藏了而已。这就导致造成额外的网络请求及加载延时问题。
项目中使用v-viewer的代码如下:
<template><div v-loading="imgLoading" v-viewer.rebuild="{ ...imgViewerConfig }" class="image-preview"><img @load="imgLoading = false" :src="fileUrl" style="visibility: hidden" /></div>
</template>
v-viewer对应的config配置
imgViewerConfig = {inline: true,button: false,navbar: false,title: false,fullscreen: true,toolbar: {prev: 0,next: 0,zoomIn: 1,zoomOut: 1,oneToOne: 1,reset: 1,play: 0,rotateLeft: 1,rotateRight: 1,flipHorizontal: 1,flipVertical: 1}}
优化的思路就是尽可能只加载一次图片。如何在不改组件的情况下,实现该目标呢?
解决方案:如果我们先通过异步请求主动加载一次图片,将图片保存在内存中,后续v-viewer组件加载内存中的图片,就可以极大地提升图片预览的速度。避免不必要的网络请求。
async function loadFileBlobLink(url: string) {const response = await fetch<BlobPart>('GET', url, {}, true)const blob = new Blob([response.data])const link = window.URL.createObjectURL(blob)return link
}
我们通过createObjectURL
创建一个URL,用于访问异步接口请求到的文件流数据。URL.createObjectURL()
是一个静态方法,用于创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期与创建它的窗口中的 document 绑定。新的对象 URL 表示指定的 File 对象或 Blob 对象。
可以通过在chrome地址栏中访问chrome://blob-internals/
,查看chrome中blob的存储占用
请注意,由 URL.createObjectURL()
创建的 URL 应当在不再需要时释放,以便浏览器可以回收任何消耗的资源。这可以通过调用 URL.revokeObjectURL()
来完成:
URL.revokeObjectURL(url);
总结
通过转换图片的加载方式,异步下载图片文件流,并通过createObjectURL
创建url引用,可以有效提升v-viewer预览图片的加载速度。在已经尝试过其他优化方案(图片压缩,提升网络带宽等)后,该方案也是进一步提升性能的可行方案。