前言
文档预览和下载功能在后台管理系统中还是挺常见的,最近就碰上了这个需求,记录一下我是怎么做的吧。
安装与引入
用到的是vue-office库,一种支持多种文件(docx、excel、pdf)预览的 vue 组件库(由于项目没用到execel,所以就没做,不过用法都一样)。
typescript
//docx文档预览组件
npm install @vue-office/docx
//pdf文档预览组件
npm install @vue-office/pdf
//引入(pdf好像没有css文件,不用引)
import VueOfficeDocx from '@vue-office/docx'
import VueOfficePdf from '@vue-office/pdf'
import '@vue-office/docx/lib/index.css'
实现代码
接口代码
要发两次请求,第一次是上传文件到后端,第二次是从后端下载文件。下载文件时需要注意的是后端返回的是文件流,在请求时需要多加一个参数 responseType:'blob,否则等等下载的文件会出现乱码。(刚开始感觉这接口地址怪怪的,半天没弄懂参数是什么,实际上就是请求第一次上传文件成功后,后端返回的地址(需要截取一下,只要后半段)。像这样:'infra/file/5/get/测试文档1.docx')
vbnet
//这是文档上的下载文件的接口地址,admin-api是baseURL
GET:/admin-api/infra/file/{configId}/get/**
// 下载文件
export const downloadFile = async (configId: string) => {
return await request.get2({ url: `${configId}`, responseType: 'blob' })
}
vue代码
我是将预览内容显示在对话框中的,通过点击预览按钮展开对话框。
xml
<template>
<el-dialog v-model="dialogTwoVisible" title="文件预览" width="800" align-center fullscreen>
<!-- docx -->
<vue-office-docx v-if="fileType == 'docx'" :src="src" />
<!-- pdf -->
<vue-office-pdf v-if="fileType == 'pdf'" :src="src" />
<!-- md -->
<div v-if="fileType == 'md'" :src="src" id="markdown-preview" v-html="html"></div>
</el-dialog>
</template>
<script lang="ts" setup>
import * as DetailApi from '@/api/algorithm/detail/index'
import MarkdownIt from 'markdown-it'
const dialogTwoVisible = ref(false) // 预览弹窗的是否展示
const html = ref() //.md文件要用到的
const fileName = ref() //文件名
const fileType = ref('') //文件类型
const src = ref('') //word和pdf文件要用到的
const formData = ref({
apiDocUrl: '' //文件上传成功后后端返回的data
}) //长这样:"http://10.3.2.243:48088/admin-api/infra/file/5/get/测试文档1.docx"
//获取文件名
const getFileName = (fileUrl: string) => {
const arr = fileUrl.split('/')
fileName.value = arr[arr.length - 1]
fileType.value = fileName.value.split('.')[1]
}
//预览按钮的回调函数
const onPreview = async () => {
//释放临时URL
URL.revokeObjectURL(src.value)
//获取文件下载请求路径
let str = formData.value.apiDocUrl
getFileName(str)
//这边是需要发请求,请求的地址就是:/infra/file/5/get/测试文档1.docx
let startIndex = str.indexOf('http://10.3.2.243:48088/admin-api') // 获取指定字符串的起始位置
if (startIndex !== -1) {
let newStr = str.slice(startIndex + 'http://10.3.2.243:48088/admin-api'.length) // 获取起始位置之后的内容
const downloadFile = await DetailApi.downloadFile(newStr)
//返回一个新的blob对象
const blob = new Blob([downloadFile])
if (fileType.value === 'md') {
//将文件内容读入内存
const reader = new FileReader()
//读取完成后触发
reader.onload = () => {
const markdownText = reader.result
const md = new MarkdownIt()
//将markdown文件转换为html页面展示
html.value = md.render(markdownText)
}
//异步按字符读取文件内容,结果用字符串形式表示
reader.readAsText(blob)
} else {
if (fileType.value === 'pdf') {
const file = new File([blob], fileName.value, {
type: 'application/pdf'
})
src.value = URL.createObjectURL(file)
} else {
const file = new File([blob], fileName.value, {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
})
src.value = URL.createObjectURL(file)
}
}
}
dialogTwoVisible.value = true
}
//下载按钮的回调函数
const handleDownload = () => {
window.open(formData.value.apiDocUrl)
}
</script>
效果图
接口文档是一个弹窗中form表单的一必填项,通过点击预览按钮打开第二个弹窗
word和pdf文件的预览看上去都差不多
下面是markdown文件的预览图
总结
前端实现文件预览和下载还是比较常见的需求,上面只是完成了基本的功能,但肯定还有更好的解决方法。功能实现后回顾感觉也不是很难,但刚开始做的时候总会各种卡壳,时间也拖了挺久。个人反思主要还是工作经验太少,相信随着工作经验的积累以后的开发速度会越来越快。