安装
@vue-office/docx
:Word文档预览组件@vue-office/excel
:Excel文档预览组件@vue-office/pdf
:PDF文档预览组件#docx文档预览组件 npm install @vue-office/docx vue-demi #excel文档预览组件 npm install @vue-office/excel vue-demi #pdf文档预览组件 npm install @vue-office/pdf vue-demi
引入
import VueOfficePdf from '@vue-office/pdf/lib/v3' import VueOfficeDocx from '@vue-office/docx/lib/v3' import VueOfficeExcel from '@vue-office/excel/lib/v3' import '@vue-office/docx/lib/v3/index.css' import '@vue-office/excel/lib/v3/index.css'
使用
<el-dialog v-model="previewDialogVisible" :title="previewFileName" width="80%" height="80%" top="5vh" :before-close="handlePreviewClose" destroy-on-close > <div class="preview-container"> <div class="preview-info"> <!-- 加载状态 --> <div v-if="loadingPreview" class="loading-container"> <el-skeleton animated> <template #template> <el-skeleton-item variant="p" style="height: 300px" /> </template> </el-skeleton> <p style="text-align: center; margin-top: 20px;">文件加载中...</p> </div> <!-- 2. 错误状态(加载失败时显示) --> <div v-else-if="previewError" class="error-container"> <el-icon color="#f56c6c" size="48" style="margin-bottom: 16px;"> <CircleCloseFilled /> </el-icon> <p style="color: #f56c6c;">{{ previewError }}</p> </div> </div> <!-- PDF文件预览 --> <VueOfficePdf v-if="currentPreviewData?.fileType === 'pdf'" :src="previewFileUrl" class="pdf-preview" @rendered="renderedHandler" @error="errorHandler" style="height: 70vh;" /> <!-- docx文件预览 --> <vue-office-docx v-else-if="['docx', 'doc'].includes(currentPreviewData?.fileType)" :src="previewFileUrl" style="height: 70vh;" @rendered="renderedHandler" @error="errorHandler" /> <!-- excel文件预览 --> <vue-office-excel v-else-if="['xlsx', 'xls'].includes(currentPreviewData?.fileType)" :src="previewFileUrl" :options="options" style="height: 70vh;" @rendered="renderedHandler" @error="errorHandler" /> <!-- 4. 不支持的文件格式(无匹配时显示) --> <div v-else class="unsupported-container"> <el-icon color="#909399" size="48" style="margin-bottom: 16px;"> <InfoFilled /> </el-icon> <p style="color: #909399;"> 不支持当前文件格式({{ currentPreviewData?.fileType || '未知' }}),请点击"下载文件"查看 </p> </div> </div> <template #footer> <div class="dialog-footer"> <el-button @click="handlePreviewClose">关闭</el-button> <!-- <el-button type="primary" @click="handleDownloadCurrentFile">下载文件</el-button>--> </div> </template> </el-dialog>
通过二进制流转换成本地Blob文件 url 进行预览
// 获取文件扩展名
const getFileExtension = (fileName) => {
if (!fileName) return ''
return fileName.slice(((fileName.lastIndexOf('.') - 1) >>> 0) + 2).toLowerCase()
}
// 名称点击事件
const handlePrintArchiveName = async (rowData) => {
console.log(rowData.fileType)
// 检查是否有预览权限
if (!permission.value.download) {
ElMessage.warning('您没有预览权限')
return
}
// 检查是否有所需的文件信息
if (!rowData.importFullFilePath && !rowData.filePath) {
ElMessage.warning('文件信息不完整,无法预览')
return
}
try {
// 重置状态
loadingPreview.value = true
previewError.value = ''
currentPreviewData.value = rowData
previewFileName.value = rowData.archiveName || '文件预览'
let quryDomainUrl = changeUrl('xzspknowledgearchive', 'common/xzspknowledgearchive/downloadfile')
const response = await commonPosts(quryDomainUrl, {
businessFlg: 'download',
moduleName: 'xzspknowledgearchive',
uniqueId: rowData.uniqueId,
fileName: rowData.filePath
}, {
repeatSubmit: false, // 按需传递防重复提交参数
responseType: 'blob' // 关键:指定响应类型为 blob
})
// 5. 生成本地预览URL(核心步骤)
const fileExt = getFileExtension(rowData.filePath)
const mimeType = getMimeTypeByExt(fileExt)
// 用正确的 MIME 类型重新包装 Blob(解决类型缺失问题)
const fileBlob = new Blob([response], { type: mimeType })
previewFileUrl.value = URL.createObjectURL(fileBlob)
// 显示预览弹窗
previewDialogVisible.value = true
// 延迟关闭加载状态,给文件一些加载时间
setTimeout(() => {
loadingPreview.value = false
}, 1000)
} catch (error) {
console.error('预览失败:', error)
loadingPreview.value = false
previewError.value = '文件预览失败,请重试'
ElMessage.error('文件预览失败,请重试')
}
}
// 新增:根据文件后缀获取 MIME 类型的工具函数
const getMimeTypeByExt = (ext) => {
const mimeMap = {
// Office 文档
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xls: 'application/vnd.ms-excel',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
doc: 'application/msword',
// 其他常见类型
pdf: 'application/pdf',
txt: 'text/plain',
zip: 'application/zip'
}
return mimeMap[ext.toLowerCase()] || 'application/octet-stream' // 默认二进制类型
}
// PDF渲染完成回调
const renderedHandler = () => {
console.log('PDF渲染完成')
loadingPreview.value = false
}
// PDF渲染错误回调
const errorHandler = (error) => {
console.error('PDF渲染失败:', error)
loadingPreview.value = false
previewError.value = 'PDF文件渲染失败,请尝试下载查看'
}
// 关闭预览弹窗
const handlePreviewClose = () => {
previewDialogVisible.value = false
previewFileUrl.value = ''
previewFileName.value = ''
currentPreviewData.value = null
loadingPreview.value = false
previewError.value = ''
}