预览组件 支持图片跟PDF

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>
  1. 支持单个和多个文件 :如果传入的 files 是单个文件(即非数组),我们将其转换为数组来统一处理。
  2. 保持现有的逻辑:单个文件和多个文件的处理方式都通过相同的代码路径来处理,避免重复代码。

代码:

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('无法预览此文件')
}

代码解析:

  1. 文件类型判断

    • const fileArray = Array.isArray(files) ? files : [files]:确保无论是传递单个文件还是多个文件,files 都是一个数组。
  2. 远程文件处理

    • 如果文件有 oss_preview_uri,说明是远程文件,判断是否为 PDF 文件。如果是 PDF,则直接通过 window.open 打开。如果是图片,则通过 a-image-preview-group 显示图片预览。
  3. 本地文件处理

    • 如果文件是本地文件(originFileObj 存在),判断是否是 PDF。如果是 PDF 文件,则直接通过 window.open 打开。如果是图片,则将其转换为 base64 数据,并显示在预览组中。
  4. 错误处理

    • 如果文件无法预览,显示错误消息。

父组件如何传递文件:

  1. 单个文件: 你可以直接传递一个文件对象。例如:
scss 复制代码
javascript
复制编辑
const file = { oss_preview_uri: 'url_to_image', name: 'image.jpg', _suffix: 'jpg' }
preview(file) // 传递单个文件
  1. 多个文件: 你也可以传递一个文件数组。例如:
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 方法就支持了单个和多个文件的预览处理,无论是远程文件还是本地文件,均能正确显示预览内容。

相关推荐
小希爸爸25 分钟前
1、中医基础入门和养生
前端·后端
神仙别闹1 小时前
基于VUE+Node.JS实现(Web)学生组队网站
前端·vue.js·node.js
下雨的Jim1 小时前
前端速成之——Script
前端·笔记
Captaincc2 小时前
使用 Copilot 代理模式构建着陆页
前端·ai编程·github copilot
zyk_5202 小时前
前端渲染pdf文件解决方案-pdf.js
前端·javascript·pdf
Apifox.2 小时前
Apifox 4月更新|Apifox在线文档支持LLMs.txt、评论支持使用@提及成员、支持为团队配置「IP 允许访问名单」
前端·人工智能·后端·ai·ai编程
划水不带桨2 小时前
大数据去重
前端
沉迷...3 小时前
手动实现legend 与 echarts图交互 通过js事件实现图标某项的高亮 显示与隐藏
前端·javascript·echarts
可观测性用观测云3 小时前
观测云数据在Grafana展示的最佳实践
前端
uwvwko3 小时前
ctfhow——web入门214~218(时间盲注开始)
前端·数据库·mysql·ctf