背景
在后台管理系统中,一些预览图片的场景,通常都是使用 `el-image-viewer` 去实现,但是如果多个地方都需要预览图片,又要重复的去写 `el-image-viewer` 以及一些重复的和预览相关的代码。
可以把预览图片的组件放在根文件,把通用的预览相关的代码放在状态管理,哪里需要预览图片,就引入调用预览方法,让根组件的预览组件预览图片。
实现
1. 状态管理用的pinia,新建preview模块文件
// /stores/modules/preview.js
import { defineStore } from "pinia";
export const PreviewStore = defineStore({
id: "PreviewStore",
state: () => {
return {
// 记录图片预览数据
imageViewer: {
show: false, // 控制图片的显现
url: "", // 预览的图片路径
close: () => {} // 关闭的回调方法
}
}
},
actions: {
// 打开图片预览的弹窗
openImageViewer({ url, close }: { url: string; close?: Function }) {
this.imageViewer = {
show: true,
url,
close: async () => {
close && (await close());
this.imageViewer.show = false;
}
};
}
}
});
2.对 el-image-viewer 进行了二次封装,增加了点击遮罩层关闭预览方法
// /components/modules/CImageViewer/index.vue
<template>
<el-image-viewer v-bind="$attrs" :url-list="[`${baseUrl}${imageViewerUrl}`]" @close="imageViewerClose" />
</template>
<script setup lang="ts">
import { onMounted, ref, nextTick, onBeforeUnmount, computed } from "vue";
import { windowOrigin } from "@/utils/util";
import { PreviewStore } from "@/stores/modules/preview";
const baseUrl = windowOrigin(); // 基础路径
const previewStore = PreviewStore();
const imageViewerUrl = computed(() => previewStore.imageViewer.url);
const imageViewerClose = computed(() => previewStore.imageViewer.close);
onMounted(() => {
nextTick(() => {
// 获取预览的遮罩层
mask.value = document.querySelector(".el-image-viewer__mask") as HTMLDivElement;
if (mask.value) {
// 遮罩层增加点击事件,关闭预览
mask.value.addEventListener("click", imageViewerClose.value);
}
});
});
onBeforeUnmount(() => {
if (mask.value) {
// 遮罩层增加点击事件,关闭预览
previewStore.imageViewer.close();
mask.value.removeEventListener("click", previewStore.imageViewer.close);
}
});
</script>
3. 在根组件App.vue 使用 CImageViewer 预览图片组件
// App.vue
<template>
... 其他文件
<!-- 全局的图片预览组件 -->
<c-image-viewer v-if="imageViewerVisible"></c-image-viewer>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { PreviewStore } from "@/stores/modules/preview";
import CImageViewer from "@/components/modules/CImageViewer/index.vue";
const previewStore = PreviewStore();
// 控制图片预览组件显现的变量
const imageViewerVisible = computed(() => previewStore.imageViewer.show);
</script>
4. 调用预览图片组件
// 需要预览图片的文件
<template>
<div class="page">
<img
class="imgUrl"
v-for="(url, index) in imageList(',')"
:key="index"
:src="url"
@click="handlePicturePreview(url)"/>
</div>
</template>
<script setup lang="ts">
import { PreviewStore } from "@/stores/modules/preview";
// ===========【 查看图片 】===========
const previewStore = PreviewStore();
const handlePicturePreview = (url: string) => {
previewStore.openImageViewer({ url });
};
</script>
总结
其实就是把根组件的图片预览显现,和调用预览方法 都是交给状态管理控制的,这样就用el-image-viewer 实现全局预览图片的功能。