ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Snowy 3.x 前端文件在线预览组件 XnFilePreview 使用指南:图片、PDF 与 Office 文档预览实战

Snowy 3.x 前端文件在线预览组件 XnFilePreview 使用指南:图片、PDF 与 Office 文档预览实战
  • 后端
  • 前端
  • 认证鉴权
  • 应用安全

【免费下载链接】Snowy

💖国内首个国密前后分离快速开发平台💖《免费商用》,基于开源技术栈精心打造,融合Vue3+AntDesignVue4+Vite5+SpringBoot3+Mp+HuTool+Sa-Token。平台内置国密加解密功能,保障前后端数据传输安全;全面支持国产化环境,适配多种机型、中间件及数据库。特别推荐:插件提供工作流、多租户、多数据源、即时通讯等高级插件,灵活接入,让您的项目开发如虎添翼。

项目地址:https://gitcode.com/xiaonuobase/Snowy
点击查看免费下载

导读

XnFilePreview 是 Snowy 3.x 管理后台(snowy-admin-web)内置的通用文件在线预览组件,开箱即用地支持图片、PDF、Word、Excel 等常见办公文件的浏览器端预览。本文以组件文档为骨架,结合组件源码、文件管理模块与后端下载鉴权实现,讲解其支持的文件类型、接入参数、内部渲染原理以及在"文件管理"页面中的完整调用链路,帮助读者在自己的业务页面中快速复用该预览能力。

一、组件是什么

XnFilePreview 位于snowy-admin-web/src/components/XnFilePreview/目录,官方 README(snowy-admin-web/src/components/XnFilePreview/README.md)对它的定位十分明确:

该组件支持图片、PDF、OFFICE、WORD 在线预览,其他类型的不支持。

也就是说,这是一个纯前端渲染型的预览组件:组件拿到文件地址(src)后,在浏览器端借助开源渲染库完成预览,不依赖后端把 Office 文档转 PDF 再回传的转换服务,因此接入成本低、部署简单,适合快速集成。

从依赖清单(package.json)可以看到组件背后依赖的渲染库及其版本:

文件类型渲染方案依赖包当前仓库版本
doc / docxVueOfficeDocx@vue-office/docx1.6.2
xls / xlsxVueOfficeExcel@vue-office/excel1.7.11
pdfVuePdfEmbedvue-pdf-embed2.1.2
png / jpg / gif / bmp / jpeg / ico / svg原生<img>标签无—

其余类型(zip、rar、txt、html、ppt 等)组件会直接渲染一个"不支持预览的文件类型"的警告提示。

二、快速接入:两个参数即可预览

README 说明了使用方式:"使用的时候直接在界面引入即可,配置相关参数就能行"。组件通过defineProps暴露两个入参(见 index.vue):

参数类型必填默认值说明
srcString是''文件的预览/下载地址,通常直接传文件记录中的downloadPath
fileTypeString否'defaults'文件类型,即文件后缀名,如docx、pdf、png

最小可运行示例:

<template> <xn-file-preview :src="previewUrl" :file-type="fileType" @goBack="onGoBack" /> </template> <script setup> const previewUrl = ref('https://xxx/dev/file/authDownload?id=123&token=xxx') const fileType = ref('pdf') const onGoBack = () => { // 返回上一页 } </script>

组件支持v-if按需挂载,也支持在弹窗、抽屉或独立路由页中承载。官方推荐通过:key或v-if控制实例重建,避免切换文件时残留上一次渲染内容。

三、参数与事件详解

3.1 src:预览地址的来源

在实际业务中,src通常不是手写的常量,而是来自后端文件列表接口返回的downloadPath字段。以文件管理模块为例(preview.vue):

const onOpen = (record) => { src.value = record.downloadPath fileType.value = record.suffix }

组件内部会把这个地址进一步加工:在src末尾追加&token=...鉴权参数:

:src="props.src + '&token=' + tool.data.get('TOKEN')"

其中tool.data.get('TOKEN')从 localStorage 读取登录凭证(实现见 snowy-admin-web/src/utils/tool.js)。这意味着传入的src应当是一个可以拼接查询参数的接口地址(而不是纯静态文件 URL),后端会基于该 token 校验登录身份。

3.2 fileType:渲染分支的依据

组件监听src变化,并将fileType统一转为小写后决定走哪个渲染分支(index.vue):

watch( () => props.src, (newVal) => { if (newVal) { fileType.value = props.fileType.toLowerCase() } }, { immediate: true, deep: true } )

因此传DOCX、Docx、docx效果相同。注意:该 watch 的触发依赖src变化,若复用同一实例仅更换fileType,需配合:key强制重建组件。

3.3 事件:goBack

组件通过defineEmits暴露唯一事件goBack(index.vue),当用户点击右上角"返回"按钮时触发。父组件据此切回列表页,例如文件管理模块中的处理:

// index.vue 中 const previewBack = () => { indexShow.value = true }

四、源码级原理:预览是怎么实现的

4.1 模板层的类型分支

组件模板按fileType依次渲染四个分支(index.vue):

<vue-office-docx v-if="fileType === 'doc' || fileType === 'docx'" :src="..." @rendered="renderedHandler" /> <vue-office-excel v-else-if="fileType === 'xls' || fileType === 'xlsx'" :src="..." @rendered="renderedHandler" @error="errorHandler" /> <vue-pdf-embed v-else-if="fileType === 'pdf'" annotation-layer text-layer :source="..." @rendered="renderedHandler" @renderingFailed="errorHandler" /> <img v-else-if="图片后缀" :src="..." class="xn-mwh" /> <a-result v-else status="warning" title="不支持预览的文件类型" />

要点说明:

  • docx / excel:通过@vue-office/docx、@vue-office/excel在浏览器端直接解析并渲染 Office 文件,组件里分别引入了对应的 CSS(@vue-office/docx/lib/index.css、@vue-office/excel/lib/index.css);
  • pdf:使用vue-pdf-embed,并开启annotation-layer(注释层)与text-layer(文本层),支持 PDF 批注渲染与文字选择;同时引入annotationLayer.css与textLayer.css保证层叠样式正确(index.vue);
  • 图片:走原生<img>标签,样式类xn-mwh将图片宽度限制为max-width: 100%,防止超宽图撑破页面。

4.2 加载态与错误兜底

组件用一个loading状态配合a-spin实现预览中的加载动画。只有 Office 与 PDF 这类需要异步渲染的文件类型才进入 loading(index.vue):

if (fileType === 'doc' || fileType === 'docx' || fileType === 'xls' || fileType === 'xlsx' || fileType === 'pdf') { loading.value = true }

渲染完成(rendered)后关闭 loading;渲染失败(error/renderingFailed)时弹出全局提示:

const renderedHandler = () => { loading.value = false } const errorHandler = () => { message.warning('渲染失败,请尝试重新打开!') }

即:成功静默展示,失败明确告警,避免用户误以为页面卡死。

4.3 工具栏与布局

模板外层提供了两个操作按钮(index.vue):

  • 下载按钮:一个指向props.src的<a-button :href>,点击在新标签页打开文件地址,等同于下载;
  • 返回按钮:触发goBack事件回到列表。

预览主体固定高度为82vh(样式.xn-ht82),在主流分辨率下能完整呈现文档内容,同时保留页面头尾;工具栏绝对定位悬浮在右上角(.go-back-button)。

五、项目内完整调用链:文件管理模块实战

5.1 预览入口:列表页如何判断"可预览"

Snowy 的文件管理列表页(views/dev/file/index.vue)通过previewDisplay(record)判断当前文件是否展示"预览"按钮:

const previewDisplay = (record) => { if (!record.suffix) return false const suffix = record.suffix.toLowerCase() if (['doc', 'docx', 'xls', 'xlsx', 'pdf', 'jpg', 'png', 'gif', 'svg', 'ico', 'tmp', 'jpeg'].includes(suffix)) { return true } }

即组件能力与列表入口严格对齐:只有组件能渲染的类型,列表才提供预览入口。其中tmp是上传临时文件的特殊后缀,同样走预览通道。

5.2 页面切换:列表 ↔ 预览

index.vue用indexShow布尔值在"列表视图"与"预览视图"之间切换(views/dev/file/index.vue):

const onPreview = (record) => { indexShow.value = false nextTick(() => { previewRef.value.onOpen(record) }) }

预览视图本身是薄封装(preview.vue):

<template> <xn-file-preview :src="src" :file-type="fileType" @goBack="emit('goBack')" /> </template>

5.3 后端配合:src 地址从哪来

record.downloadPath由后端填充。在 DevFileServiceImpl.java 中可以看到地址生成逻辑:

// 公开文件使用带签名的 download 接口 String sign = generateDownloadSign(fileId); downloadUrl = apiUrl + "/dev/file/download?id=" + fileId + "&sign=" + sign; devFile.setDownloadPath(downloadUrl);

签名通过 HmacSHA256 对文件 id 计算并 Base64 编码(generateDownloadSign,见同文件 L419-L423),下载接口收到请求后先验签再放行(L127-L135):

public void download(DevFileDownloadParam devFileDownloadParam, HttpServletResponse response) throws IOException { // 验证签名 if (!verifyDownloadSign(devFileDownloadParam.getId(), devFileDownloadParam.getSign())) { CommonResponseUtil.renderError(response, "下载链接无效,请使用正确的下载地址"); return; } unifiedDownload(devFileIdParam, response, false); }

而对于需要登录授权的文件(isDownloadAuth = true),后端提供authDownload接口(DevFileController.java),校验登录 token 后才允许下载。这正是组件里往src追加&token=...的原因——预览授权文件时,需要把当前登录态一并带给后端。

整个调用链可概括为:

文件列表接口 → record.downloadPath(带签名/鉴权的接口地址) ↓ 列表页 previewDisplay 判定可预览 → onPreview 切换视图 ↓ preview.vue 将 downloadPath 作为 src、suffix 作为 fileType 传给 XnFilePreview ↓ XnFilePreview 追加 &token=... → 按 fileType 分发到 docx/excel/pdf/img 渲染分支

六、可预览类型速查与扩展提示

结合组件渲染分支与列表入口,最终可预览类型如下:

类别后缀渲染方式
图片png、jpg、jpeg、gif、bmp、ico、svg原生 img
办公文档doc、docx@vue-office/docx
表格xls、xlsx@vue-office/excel
PDFpdfvue-pdf-embed
其他一律不支持a-result 警告提示

扩展提示(基于源码结构推断,非仓库既定能力):

  • 若要支持 ppt/pptx,需引入类似@vue-office/pptx的渲染库并在模板中增加分支,同时把对应后缀加入previewDisplay白名单;
  • 由于组件渲染依赖浏览器端解析,超大文件建议后端先做大小限制或分批转换,避免首屏渲染卡顿;
  • 预览地址默认是接口地址,若后续切换到静态 OSS 直链,需同步调整 token 拼接逻辑,避免在签名直链上追加无效参数。

七、小结

XnFilePreview 是 Snowy 3.x 中一个轻量而实用的通用预览组件:两个入参 + 一个返回事件即可接入,图片与 PDF/Office 渲染各司其职,加载态与错误提示完整兜底。结合文件管理模块的"列表判定 → 视图切换 → 鉴权地址拼接"链路,读者既能直接复用它,也能以此为模板扩展更多文件类型的在线预览能力。

相关仓库路径速查:

  • 组件文档:snowy-admin-web/src/components/XnFilePreview/README.md
  • 组件实现:snowy-admin-web/src/components/XnFilePreview/index.vue
  • 文件管理列表:snowy-admin-web/src/views/dev/file/index.vue
  • 预览封装页:snowy-admin-web/src/views/dev/file/preview.vue
  • 后端下载鉴权:snowy-plugin/snowy-plugin-dev/src/main/java/vip/xiaonuo/dev/modular/file/service/impl/DevFileServiceImpl.java
  • 后端
  • 前端
  • 认证鉴权
  • 应用安全

【免费下载链接】Snowy

💖国内首个国密前后分离快速开发平台💖《免费商用》,基于开源技术栈精心打造,融合Vue3+AntDesignVue4+Vite5+SpringBoot3+Mp+HuTool+Sa-Token。平台内置国密加解密功能,保障前后端数据传输安全;全面支持国产化环境,适配多种机型、中间件及数据库。特别推荐:插件提供工作流、多租户、多数据源、即时通讯等高级插件,灵活接入,让您的项目开发如虎添翼。

项目地址:https://gitcode.com/xiaonuobase/Snowy
点击查看免费下载

相关推荐

上一篇:RedisShake 使用教程
下一篇:Havenask搜索引擎终极指南:10个核心功能详解与实战应用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进