Word Inline Viewport(浏览器内 Word 预览)
用 docx-preview 在浏览器中渲染 .docx,不依赖 Office / WPS。本 Skill 定义一套可复用的接入流程,并强制执行「每次加载成功必须给出反馈」。
何时启用
- 用户要做 Word / docx 在线预览
- 明确要求用
docx-preview、无需安装 Office - 需要上传后立即在页面内展示文档内容
- 需要统一「预览成功 / 失败」的用户反馈
硬约束
- 只处理
.docx(OOXML)。.doc(旧二进制)不支持;遇到时提示用户另存为.docx。 - 不调用 Office Online、OnlyOffice、后端转 PDF 等替代方案,除非用户明确改需求。
- 每次
renderAsync成功后必须触发 Load Signal(见下文)。禁止静默成功。 - 预览容器在渲染前 清空;组件销毁时清理 DOM / 状态,避免残留。
- 大文件注意:优先
arrayBuffer读入;不要把整份文档塞进localStorage。
标准工作流
复制并勾选:
Word Inline Viewport
- [ ] 确认依赖 docx-preview 已安装(或写入 package.json)
- [ ] 准备预览宿主 DOM(ref / id)
- [ ] 接入文件选择(input / el-upload / 拖拽)
- [ ] 校验扩展名与 MIME
- [ ] renderAsync(arrayBuffer, host)
- [ ] 成功 → Load Signal(文案 + Toast/Message)
- [ ] 失败 → 错误反馈 + 清空宿主
- [ ] 补充基础样式(滚动、背景、最大高度)
Step 1:依赖
npm i docx-preview
# 或
pnpm add docx-preview
导入:
import { renderAsync } from 'docx-preview';
Step 2:宿主与清空
host.innerHTML = '';
await renderAsync(buffer, host, undefined, {
className: 'docx-viewport',
inWrapper: true,
ignoreWidth: false,
breakPages: true,
});
- 第二个参数:内容挂载节点(必填)
- 第三个参数:样式挂载节点(可选,默认同宿主)
- 第四个参数:渲染选项(见 reference.md)
Step 3:文件校验
function assertDocx(file: File): void {
const name = file.name.toLowerCase();
if (!name.endsWith('.docx')) {
throw new Error('仅支持 .docx 文件,请另存为 Word 2007+ 格式后再试');
}
}
Step 4:Load Signal(强制)
每次预览成功后,必须同时做到:
| 通道 | 要求 |
|---|---|
| 界面文案 | 更新提示行,至少含文件名,建议含页数或耗时 |
| Toast / Message | 弹出成功提示(Element Plus 用 ElMessage.success) |
| 可选日志 | console.info('[docx-viewport] loaded', meta) 便于排查 |
成功反馈文案模板(可按项目微调,但不得省略):
预览成功:{fileName}({elapsedMs}ms)
失败时:
预览失败:{reason}
并清空宿主内容。
Step 5:Vue 3 + Element Plus 推荐形态
本仓库常见栈为 Vue 3.2 + Element Plus 2.2。优先:
el-upload:auto-upload=false,accept=".docx"ref指向宿主divElMessage.success/ElMessage.error作为 Toast 通道
完整片段见 templates/vue-el-preview.md。
Load Signal 协议(不可跳过)
type LoadSignalMeta = {
fileName: string;
byteLength: number;
elapsedMs: number;
source: 'upload' | 'url' | 'buffer';
};
/** 预览成功后必须调用;禁止注释掉或改成 no-op */
function emitDocxLoadSignal(meta: LoadSignalMeta): void {
const text = `预览成功:${meta.fileName}(${meta.elapsedMs}ms)`;
// 1) 界面文案
hintRef.value = text;
// 2) Toast
ElMessage.success(text);
// 3) 可选诊断
console.info('[docx-viewport] loaded', meta);
}
调用时机:
const t0 = performance.now();
await renderAsync(buffer, host);
emitDocxLoadSignal({
fileName: file.name,
byteLength: buffer.byteLength,
elapsedMs: Math.round(performance.now() - t0),
source: 'upload',
});
反模式(禁止):
renderAsync成功后只改innerHTML、不提示用户- 用
console.log代替用户可见反馈 - 仅在首次成功提示,后续同一会话再次上传不再提示
从 URL / 接口加载
const res = await fetch(docxUrl);
if (!res.ok) throw new Error(`下载失败 HTTP ${res.status}`);
const buffer = await res.arrayBuffer();
await renderAsync(buffer, host);
emitDocxLoadSignal({ fileName: fileNameFromUrl(docxUrl), byteLength: buffer.byteLength, elapsedMs, source: 'url' });
注意 CORS:跨域需服务端放行;鉴权 URL 带上项目既有 token 头。
样式基线
.docx-viewport-host {
max-height: 70vh;
overflow: auto;
background: #f5f5f5;
padding: 12px;
border: 1px solid var(--el-border-color, #dcdfe6);
}
更多选项与排错见 reference.md。
Agent 交付检查
完成实现后向用户确认:
- 能否选择 / 传入
.docx并在页面内看到内容 - 每次成功是否都出现 Load Signal(文案 + Toast)
- 非
.docx/ 损坏文件是否有明确错误提示 - 是否未引入 Office 依赖或外部在线 Office 服务
附加资源
- API 与选项:reference.md
- Vue + Element Plus 模板:templates/vue-el-preview.md