在管理系统开发过程中,我们不可避免需要预览一些上传的图片。小编在开发过程中就遇到需要实现在列表上点击"查看"按钮预览该条记录上的所有图片。
项目所用技术栈:vue、element ui
我们都知道el-image
组件可以通过previewSrcList
开启预览大图的功能,那么是否可以基于该组件实现预览功能呢?当然是可以的。
下面就是小编开发的图片预览组件,其原理就是通过手动触发el-image的预览大图功能
js
<template>
<!-- 图片预览 -->
<el-image
id="previewImage"
style="
opacity: 0;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
"
:src="logo"
:preview-src-list="imagesList"
fit="fill"
@click.stop="handleClick"
/>
</template>
<script lang="ts">
import Vue from 'vue'
// 给个默认的图片地址,使el-image相关的dom元素都能存在
import logo from '@/assets/images/logo.png'
import { Loading } from 'element-ui'
import { showPic } from '@/api/common'
export default Vue.extend({
name: 'SeeImages',
props: ['imagesDialogVisible', 'imageIdList'],
data() {
return { logo, imagesList: [], loadingInstance: null }
},
created() {
// 根据图片id调用接口获取到图片的url
this.loadingInstance = Loading.service({ fullscreen: true })
const promiseArr = []
for (const i of this.imageIdList) {
// thumbnailType缩略图类型0-非缩略图 1-缩略图
promiseArr.push(showPic({ id: i, thumbnailType: 0 }))
}
Promise.all(promiseArr)
.then((res) => {
const images = []
res.forEach((item) => {
images.push(
'data:image/png;base64,' +
btoa(
new Uint8Array(item.data).reduce(
(data, byte) => data + String.fromCharCode(byte),
''
)
)
)
})
this.imagesList = images
this.$nextTick(() => {
// 触发el-image的预览功能
const element = document.querySelectorAll(
'#previewImage'
)[0] as HTMLElement
if (element) {
element.click()
}
})
})
.finally(() => {
this.loadingInstance.close()
})
},
methods: {
handleClick() {
// 关闭预览的时候移除组件
const that = this
setTimeout(function () {
const domImageMask = document.querySelector('.el-image-viewer__wrapper')
if (!domImageMask) {
return
}
domImageMask.addEventListener('click', (e) => {
if (
[
'el-image-viewer__btn el-image-viewer__prev',
'el-image-viewer__btn el-image-viewer__next',
'el-image-viewer__btn el-image-viewer__actions',
'el-image-viewer__actions__inner',
'el-image-viewer__canvas'
].includes((e.target as any).parentNode?.className || '')
) {
return
}
that.$emit('update:imagesDialogVisible', false)
})
}, 300)
}
}
})
</script>