js
<template>
<a-image-preview-group
:preview="{
current: previewCurrent,
visible: previewVisible,
onVisibleChange: (val) => (previewVisible = val),
}"
>
<!-- 渲染多个图片 -->
<a-image v-for="(src, index) in previewSources" :key="index" :src="src" :width="0" :height="0" />
</a-image-preview-group>
</template>
<script setup>
import { ref, defineExpose } from 'vue'
import { message } from 'ant-design-vue'
import { downfile } from '@/servers/Common'
const previewVisible = ref(false)
const previewSources = ref([])
const previewCurrent = ref(0)
const getBase64 = (file) =>
new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => resolve(reader.result)
reader.onerror = (error) => reject(error)
})
// 需要父组件传入的下载函数
const preview = async (files, currentIndex = 0) => {
// 确保传入的是文件数组,即使是单个文件也包裹成数组
const fileArray = Array.isArray(files) ? files : [files]
if (fileArray.length === 0) {
message.error('没有可预览的文件')
return
}
const firstFile = fileArray[0] // 预览时的第一个文件(如果需要按顺序展示)
const isPdf = firstFile._suffix?.toLowerCase() === 'pdf' || firstFile.name?.toLowerCase().endsWith('.pdf')
// 远程文件
if (firstFile.oss_preview_uri) {
if (isPdf) {
const response = await downfile(firstFile.id)
const blob = new Blob([response.data], {
type: `${response.headers['content-type']};charset=utf-8`,
})
const url = URL.createObjectURL(blob)
window.open(url, '_blank') // ✅ 直接打开 PDF
} else {
// 支持多张图片预览
previewSources.value = fileArray.map((file) => file.oss_preview_uri)
previewCurrent.value = currentIndex
previewVisible.value = true
}
return
}
// 本地文件
if (firstFile.originFileObj) {
const isLocalPdf = firstFile.originFileObj.type === 'application/pdf'
if (isLocalPdf) {
const url = URL.createObjectURL(firstFile.originFileObj)
window.open(url, '_blank') // ✅ 直接打开 PDF
} else {
// 图片转换为 base64 支持多图
previewSources.value = await Promise.all(fileArray.map((file) => getBase64(file.originFileObj)))
previewCurrent.value = currentIndex
previewVisible.value = true
}
return
}
message.error('无法预览此文件')
}
defineExpose({ preview })
</script>
- 支持单个和多个文件 :如果传入的
files
是单个文件(即非数组),我们将其转换为数组来统一处理。 - 保持现有的逻辑:单个文件和多个文件的处理方式都通过相同的代码路径来处理,避免重复代码。
代码:
javascript
javascript
const preview = async (files, currentIndex = 0) => {
// 确保传入的是文件数组,即使是单个文件也包裹成数组
const fileArray = Array.isArray(files) ? files : [files]
if (fileArray.length === 0) {
message.error('没有可预览的文件')
return
}
const firstFile = fileArray[0] // 预览时的第一个文件(如果需要按顺序展示)
const isPdf = firstFile._suffix?.toLowerCase() === 'pdf' || firstFile.name?.toLowerCase().endsWith('.pdf')
// 远程文件
if (firstFile.oss_preview_uri) {
if (isPdf) {
const response = await downfile(firstFile.id)
const blob = new Blob([response.data], {
type: `${response.headers['content-type']};charset=utf-8`,
})
const url = URL.createObjectURL(blob)
window.open(url, '_blank') // ✅ 直接打开 PDF
} else {
// 支持多张图片预览
previewSources.value = fileArray.map((file) => file.oss_preview_uri)
previewCurrent.value = currentIndex
previewVisible.value = true
}
return
}
// 本地文件
if (firstFile.originFileObj) {
const isLocalPdf = firstFile.originFileObj.type === 'application/pdf'
if (isLocalPdf) {
const url = URL.createObjectURL(firstFile.originFileObj)
window.open(url, '_blank') // ✅ 直接打开 PDF
} else {
// 图片转换为 base64 支持多图
previewSources.value = await Promise.all(
fileArray.map((file) => getBase64(file.originFileObj))
)
previewCurrent.value = currentIndex
previewVisible.value = true
}
return
}
message.error('无法预览此文件')
}
代码解析:
-
文件类型判断:
const fileArray = Array.isArray(files) ? files : [files]
:确保无论是传递单个文件还是多个文件,files
都是一个数组。
-
远程文件处理:
- 如果文件有
oss_preview_uri
,说明是远程文件,判断是否为 PDF 文件。如果是 PDF,则直接通过window.open
打开。如果是图片,则通过a-image-preview-group
显示图片预览。
- 如果文件有
-
本地文件处理:
- 如果文件是本地文件(
originFileObj
存在),判断是否是 PDF。如果是 PDF 文件,则直接通过window.open
打开。如果是图片,则将其转换为 base64 数据,并显示在预览组中。
- 如果文件是本地文件(
-
错误处理:
- 如果文件无法预览,显示错误消息。
父组件如何传递文件:
- 单个文件: 你可以直接传递一个文件对象。例如:
scss
javascript
复制编辑
const file = { oss_preview_uri: 'url_to_image', name: 'image.jpg', _suffix: 'jpg' }
preview(file) // 传递单个文件
- 多个文件: 你也可以传递一个文件数组。例如:
scss
javascript
复制编辑
const files = [ { oss_preview_uri: 'url_to_image_1', name: 'image1.jpg', _suffix: 'jpg' }, { oss_preview_uri: 'url_to_image_2', name: 'image2.jpg', _suffix: 'jpg' },]
preview(files) // 传递多个文件
渲染逻辑:
无论是单个文件还是多个文件,a-image-preview-group
会根据传入的 previewSources
数组动态渲染,并且支持显示当前选中的文件。
arduino
html
复制编辑
<a-image-preview-group
:preview="{
current: previewCurrent,
visible: previewVisible,
onVisibleChange: (val) => (previewVisible = val),
}"
>
<a-image v-for="(src, index) in previewSources" :key="index" :src="src" :width="0" :height="0" />
</a-image-preview-group>
这样,preview
方法就支持了单个和多个文件的预览处理,无论是远程文件还是本地文件,均能正确显示预览内容。