导出菜单应按场景收敛:内部系统用csv+excel,对外交付用pdf+docx,临时预览走浏览器打印;csv须加u+feff bom头防中文乱码,excel导出需规避table_to_sheet缺陷,pdf优先后端生成。

导出菜单要支持哪些格式,得看用户真实需求
不是所有导出功能都要塞进一个菜单。实际项目里,CSV适合运营查表、Excel(.xlsx)适合带公式或多人协作、PDF用于归档或打印、DOCX则偏向可编辑交付。硬塞五种格式反而让用户困惑。
建议按场景收敛:内部系统导出数据 → CSV + Excel;对外交付文档 → PDF + DOCX;临时预览 → 浏览器打印(不进菜单,用快捷键或右键)。
-
CSV必须加\ufeffBOM 头,否则 Excel 打开中文全乱码 -
Excel导出别直接用table_to_sheet,表格含合并单元格、样式或跨页时会丢内容,优先走后端生成 -
PDF用前端生成时,html2canvas截图会模糊,尤其小字号或细线;jsPDF原生绘图又写起来太重,折中方案是只对纯文本区块用html2canvas,复杂布局改用服务端渲染
菜单交互不能只靠按钮堆砌
导出是耗时操作,用户点击后没反馈就容易连点。菜单本身要带状态:禁用态 + loading 图标 + 进度提示(比如“正在生成 Excel…”),而不是弹个空 alert。
还要防误操作:导出前检查目标 DOM 是否存在、是否为空;导出 PDF 时若页面含动态图表(如 ECharts),得等 chart.setOption 完成后再触发截图,否则导出白板。
- 菜单项用
<button type="menuitem"></button>而非<div>,保障键盘导航和屏幕阅读器可访问 <li>避免在 Vue/React 组件里用 <code>document.getElementById取 DOM,改用 ref 或querySelector配合生命周期钩子 - 导出失败时,错误信息要具体,比如
"导出失败:表格数据为空",而不是"操作异常" - CDN 方式必须确保
html-docx-js在 Vue 实例创建前加载完成 - npm 方式推荐在导出函数内做懒加载:
const htmlDocx = await import('htmldocx'),避免首屏白屏 - SheetJS 不要混用
xlsx.full.min.js和xlsx.min.js,后者不支持table_to_sheet - 克隆时用
node.cloneNode(true),再遍历删掉data-*属性和onclick等事件绑定 - 若原 HTML 含相对路径图片(如
src="./img/logo.png"),克隆后需转为绝对 URL,否则导出 DOCX 里图片丢失 - PDF 导出前调用
window.getComputedStyle检查字体是否加载完成,fontFamily返回"serif"就说明 Web Font 还没就绪
HTMLDocx 和 SheetJS 的导入方式差异直接影响稳定性
htmldocx(注意包名是小写)和 xlsx(SheetJS)都依赖全局对象注入,但行为不同:htmldocx 的 asBlob 方法不处理内联样式,font-size: 12px 会失效;xlsx 的 table_to_sheet 会把 <th> 当普通单元格,需手动设 <code>cell.v = "标题"; cell.s = { font: { bold: true } } 才能加粗。
更关键的是资源加载时机:CDN 引入时,<script></script> 标签顺序错位会导致 htmlDocx is not defined;npm 安装后若在 Vue 3 的 setup() 里直接调用,可能因模块未初始化报错。
导出菜单的 DOM 结构必须隔离样式污染
很多团队把导出菜单写在 <header></header> 或 <aside></aside> 里,结果导出 PDF 时把整个侧边栏、顶部导航都截进去了。根本原因是 html2canvas 或 htmldocx 默认作用于传入的 DOM 节点及其全部后代,而没人清理 class 或 style。
正确做法是:导出前克隆目标内容到隐藏 <div id="export-target">,移除无关 class、内联 style、脚本标签;导出完立即销毁该节点。不要试图用 CSS <code>@media print 控制,html2canvas 不识别媒体查询。











