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预览图片的加载速度。在已经尝试过其他优化方案(图片压缩,提升网络带宽等)后,该方案也是进一步提升性能的可行方案。