with one click
support
为 vue-files-preview 添加新文件类型预览支持。当用户提到"添加支持"、"新文件类型"、"support"时使用。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
为 vue-files-preview 添加新文件类型预览支持。当用户提到"添加支持"、"新文件类型"、"support"时使用。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
| name | support |
| description | 为 vue-files-preview 添加新文件类型预览支持。当用户提到"添加支持"、"新文件类型"、"support"时使用。 |
为 vue-files-preview 组件库添加新的文件格式预览能力。
在开始之前,需要确认以下信息(如用户未提供则主动询问):
ppt、msg、svg 等['ppt', 'pptx', 'pptm']text - 文本内容(代码、纯文本、Markdown 等)arrayBuffer - 二进制数据(Office 文档、EPUB 等)image - 图片类型(直接生成 Object URL)pdf - PDF 文件video - 视频文件pptx-preview、@kenjiuno/msgreader 等packages/preview/
├── preview.interface.ts # PreviewType 枚举、PreviewProps 接口、IPreviewRule 等类型定义
├── preview.const.ts # PreviewRules 规则映射、渲染类型分类列表
├── utils/utils.ts # getFileType、getFileRenderByFile、mimeToExtMap 等工具函数
└── supports/ # 各预览组件目录
├── {type}-preview/
│ ├── index.ts # 组件导出和全局注册
│ └── index.vue # 预览组件实现
└── vue-files-preview/ # 主入口组件(路由分发)
pnpm add <package-name>
注意事项:
@vue-office 系列的包,导入路径必须使用 lib/v3/index.js(因为 postinstall 脚本在 pnpm 下可能未正确执行)ls node_modules/<package>/lib/v3/ 查看是否存在 CSS 文件在 packages/preview/preview.interface.ts 的 PreviewType 枚举中添加:
export enum PreviewType {
// ... 已有类型
NEW_TYPE = 'new_type', // 新类型
}
命名规范:
PPT、MSG、XLSX'ppt'、'msg'、'xlsx'创建目录 packages/preview/supports/{type}-preview/,包含两个文件:
根据渲染方式选择对应的模板:
模板 A:使用第三方 Vue 组件渲染(如 @vue-office 系列)
<script lang='ts' setup>
import ThirdPartyComponent from '<package>/lib/v3/index.js'
// 如有 CSS:import '<package>/lib/v3/index.css'
import {ref, watch} from 'vue'
import type {PreviewProps} from '../../preview.interface'
import {getFileRenderByFile, getFileRenderByUrl} from '../../utils/utils'
const props = withDefaults(
defineProps<PreviewProps>(),
{
url: () => null,
file: () => null,
},
)
const fileRender = ref(null)
watch(
() => props.file,
(file) => {
if (file) {
getFileRenderByFile(file).then((render) => {
fileRender.value = render
})
}
},
{immediate: true},
)
watch(
() => props.url,
(url) => {
if (url && !props.file) {
getFileRenderByUrl(url).then((render) => {
fileRender.value = render
})
}
},
{immediate: true},
)
const emit = defineEmits<{
rendered: []
error: [error: Error]
}>()
function renderedHandler(): void {
emit('rendered')
}
function errorHandler(e: Error): void {
emit('error', e)
}
</script>
<template>
<div class="{type}-preview">
<ThirdPartyComponent :src="fileRender" @rendered="renderedHandler" @error="errorHandler"/>
</div>
</template>
<style scoped lang='scss'></style>
模板 B:自定义渲染逻辑(如 msg-preview)
<script lang='ts' setup>
import {ref, watch} from 'vue'
import type {PreviewProps} from '../../preview.interface'
import {getFileRenderByFile, getFileRenderByUrl} from '../../utils/utils'
const props = withDefaults(
defineProps<PreviewProps>(),
{
url: () => null,
file: () => null,
},
)
const emit = defineEmits<{
rendered: []
error: [error: Error]
}>()
const renderData = ref(null)
function parseData(data: ArrayBuffer | string): void {
try {
// 自定义解析逻辑
renderData.value = /* 解析结果 */
emit('rendered')
} catch (e) {
emit('error', e instanceof Error ? e : new Error('Failed to parse file'))
}
}
watch(
() => props.file,
(file) => {
if (file) {
getFileRenderByFile(file).then((render) => {
parseData(render)
}).catch((e: Error) => {
emit('error', e)
})
}
},
{immediate: true},
)
watch(
() => props.url,
(url) => {
if (url && !props.file) {
getFileRenderByUrl(url).then((render) => {
parseData(render)
}).catch((e: Error) => {
emit('error', e)
})
}
},
{immediate: true},
)
</script>
<template>
<div class="{type}-preview">
<!-- 自定义渲染模板 -->
</div>
</template>
<style scoped lang='scss'>
/* 自定义样式 */
</style>
模板 C:简单媒体渲染(如 pic-preview、video-preview)
<script lang='ts' setup>
import {ref, watch} from 'vue'
import type {PreviewProps} from '../../preview.interface'
import {getFileRenderByFile, getFileRenderByUrl} from '../../utils/utils'
const props = withDefaults(
defineProps<PreviewProps>(),
{
url: () => null,
file: () => null,
},
)
const emit = defineEmits<{
rendered: []
error: [error: Error]
}>()
const fileRender = ref(null)
watch(
() => props.file,
(file) => {
if (file) {
getFileRenderByFile(file).then((render) => {
fileRender.value = render
}).catch((e: Error) => {
emit('error', e)
})
}
},
{immediate: true},
)
watch(
() => props.url,
(url) => {
if (url && !props.file) {
getFileRenderByUrl(url).then((render) => {
fileRender.value = render
}).catch((e: Error) => {
emit('error', e)
})
}
},
{immediate: true},
)
</script>
<template>
<div class="{type}-preview">
<!-- 使用 fileRender 作为 src -->
<img :src="fileRender" @load="emit('rendered')" @error="emit('error', new Error('Load failed'))">
</div>
</template>
<style scoped lang='scss'></style>
import type {App as Application} from 'vue'
import {TypeName}Preview from './index.vue'
{TypeName}Preview.install = (app: Application) => {
app.component('{TypeName}Preview', {TypeName}Preview)
}
export default {TypeName}Preview
命名规范:
{type}-preview(小写连字符),如 ppt-preview、msg-preview{TypeName}Preview(PascalCase),如 PptPreview、MsgPreview在 packages/preview/preview.const.ts 中:
import {TypeName}Preview from './supports/{type}-preview/index'
export const textFilePreviewTypeList = [...] // 文本类型
export const arrayBufferPreviewTypeList = [...] // 二进制数据类型
export const imagePreviewTypeList = [...] // 图片类型
export const pdfPreviewTypeList = [...] // PDF 类型
export const videoPreviewTypeList = [...] // 视频类型
[PreviewType.NEW_TYPE]: {
name: '',
component: {TypeName}Preview,
type: PreviewType.NEW_TYPE,
accept: ['ext1', 'ext2', 'ext3'], // 支持的文件扩展名
},
在 packages/preview/utils/utils.ts 的 mimeToExtMap 中添加对应映射:
const mimeToExtMap: Record<string, string> = {
// ... 已有映射
'application/vnd.ms-powerpoint': 'ppt',
'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
}
此步骤确保 Blob 类型的文件能通过 MIME type 正确推断文件类型。
npm run build
确保 ES 和 UMD 两种格式均构建成功,无类型错误。
在 example/src/App.vue 的 sampleLinks 数组中添加测试链接:
const sampleLinks = [
// ... 已有链接
'https://example.com/test.newtype',
]
完成后逐项确认:
PreviewType 枚举已添加新类型supports/{type}-preview/index.vue 组件已创建supports/{type}-preview/index.ts 导出已创建preview.const.ts 已导入组件preview.const.ts 渲染类型分类列表已添加preview.const.ts PreviewRules 已注册(component 指向实际组件而非 UnknownPreview)utils/utils.ts mimeToExtMap 已添加 MIME 映射npm run build 构建通过rendered 和 error 事件 - 主组件依赖这两个事件控制 loading 状态file 和 url 两种输入 - 通过两个 watch 分别处理,url 仅在没有 file 时生效File | Blob - 不能假设 file 一定有 .name 属性lib/v3/index.js 而非包根路径,避免 pnpm 下 postinstall 脚本问题