[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"i-ri:search-line":3,"i-ri:moon-line":8,"i-ri:sun-line":10,"i-ri:menu-3-line":12,"i-ri:close-line":14,"notes-module-items-frontend":16,"notes-page-frontend-03-printing\u002F01-pagination-fonts":42,"i-ri:arrow-left-s-line":182,"i-ri:menu-2-line":184,"i-ri:arrow-right-s-line":186,"i-ep:copy-document":188},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"currentColor\" d=\"m18.031 16.617l4.283 4.282l-1.415 1.415l-4.282-4.283A8.96 8.96 0 0 1 11 20c-4.968 0-9-4.032-9-9s4.032-9 9-9s9 4.032 9 9a8.96 8.96 0 0 1-1.969 5.617m-2.006-.742A6.98 6.98 0 0 0 18 11c0-3.867-3.133-7-7-7s-7 3.133-7 7s3.133 7 7 7a6.98 6.98 0 0 0 4.875-1.975z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cpath fill=\"currentColor\" d=\"M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12S6.477 2 12 2h.1A6.98 6.98 0 0 0 10 7m-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938A8 8 0 0 0 4 12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cpath fill=\"currentColor\" d=\"M12 18a6 6 0 1 1 0-12a6 6 0 0 1 0 12m0-2a4 4 0 1 0 0-8a4 4 0 0 0 0 8M11 1h2v3h-2zm0 19h2v3h-2zM3.515 4.929l1.414-1.414L7.05 5.636L5.636 7.05zM16.95 18.364l1.414-1.414l2.121 2.121l-1.414 1.414zm2.121-14.85l1.414 1.415l-2.121 2.121l-1.414-1.414zM5.636 16.95l1.414 1.414l-2.121 2.121l-1.414-1.414zM23 11v2h-3v-2zM4 11v2H1v-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm6 7h12v2H9zm-6 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"currentColor\" d=\"m12 10.587l4.95-4.95l1.414 1.414l-4.95 4.95l4.95 4.95l-1.415 1.414l-4.95-4.95l-4.949 4.95l-1.414-1.415l4.95-4.95l-4.95-4.95L7.05 5.638z\"\u002F>",[17,22,26,30,34,38],{"path":18,"title":19,"meta":20},"\u002Fnotes\u002Ffrontend\u002F01-forms\u002F01-clear-semantics","表单清空后，旧数据为什么又回来了？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},"2026-11-05T09:47:15.000Z",{"path":23,"title":24,"meta":25},"\u002Fnotes\u002Ffrontend\u002F01-forms\u002F02-async-persistence","保存请求回来时，文档已经变了",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":27,"title":28,"meta":29},"\u002Fnotes\u002Ffrontend\u002F02-canvas\u002F01-geometry-history","拖一下画布，为什么撤销回不去了？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":31,"title":32,"meta":33},"\u002Fnotes\u002Ffrontend\u002F03-printing\u002F01-pagination-fonts","预览正常，PDF 为何多一页或缺字？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":35,"title":36,"meta":37},"\u002Fnotes\u002Ffrontend\u002F04-web-delivery\u002F01-cache-diagnosis","API 更新了，博客页面为什么还是旧的？",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"path":39,"title":40,"meta":41},"\u002Fnotes\u002Ffrontend","前端与 Web 工程",{"date":-1,"tags":-1,"summary":-1,"lastUpdated":21},{"id":43,"type":44,"sourcePath":45,"routePath":31,"path":31,"title":32,"description":46,"updatedAt":21,"meta":47,"body":56,"toc":175},"bm90ZTpub3Rlcy9mcm9udGVuZC8wMy1wcmludGluZy8wMS1wYWdpbmF0aW9uLWZvbnRzLm1k","note","notes\u002Ffrontend\u002F03-printing\u002F01-pagination-fonts.md","模板报表在浏览器里看着正常，导出 PDF 却多了一页，有时新页只剩一条窄小内容；另一些报表则缺中文。这些现象看起来都发生在打印时，原因却不同。",{"id":43,"type":44,"sourcePath":45,"slug":48,"title":32,"updatedAt":21,"description":46,"tags":49,"date":53,"comment":54,"summary":55,"lastUpdated":21},"frontend\u002F03-printing\u002F01-pagination-fonts",[50,51,52],"frontend","PDF","报表","2026-04-30",true,"模板报表的页面尺寸和导出字体各有链路。先算可打印区域，再检查导出资源，避免只靠调整页面样式反复试。",{"type":57,"children":58},"root",[59,67,72,77,84,89,94,107,112,118,123,128,133,139,144,149,154,159,165,170],{"type":60,"tag":61,"props":62,"children":64},"element","h1",{"id":63},"预览正常pdf-为何多一页或缺字",[65],{"type":66,"value":32},"text",{"type":60,"tag":68,"props":69,"children":70},"p",{},[71],{"type":66,"value":46},{"type":60,"tag":68,"props":73,"children":74},{},[75],{"type":66,"value":76},"这里的报表由引擎读取模板和数据，再生成预览与 PDF。模板除了纸张方向，还保存正文区域、页眉页脚和尺寸。此前出现过横向纸张仍沿用纵向正文高度、内容超过可打印宽度，以及字体尚未准备好等问题。",{"type":60,"tag":78,"props":79,"children":81},"h2",{"id":80},"多出一页通常先看什么",[82],{"type":66,"value":83},"多出一页，通常先看什么？",{"type":60,"tag":68,"props":85,"children":86},{},[87],{"type":66,"value":88},"先核对内容是否真的落在一页可打印区域内，再看分页规则。只调整显示缩放，可能让预览装得下，却没有改变导出引擎使用的物理尺寸。",{"type":60,"tag":68,"props":90,"children":91},{},[92],{"type":66,"value":93},"以 A4 为例，纸张是 210 mm × 297 mm，横向时交换；正文空间还要扣掉边距与页眉页脚：",{"type":60,"tag":95,"props":96,"children":101},"pre",{"className":97,"code":99,"language":66,"meta":100},[98],"language-text","printableWidth  = pageWidth - leftMargin - rightMargin\nprintableHeight = pageHeight - topMargin - bottomMargin\n                  - pageHeaderHeight - pageFooterHeight\n","",[102],{"type":60,"tag":103,"props":104,"children":105},"code",{"__ignoreMap":100},[106],{"type":66,"value":99},{"type":60,"tag":68,"props":108,"children":109},{},[110],{"type":66,"value":111},"切到横向后，页面高度变小，正文却仍按纵向预留，就可能生成额外一页。宽度超出时，右边一小条内容也可能被分到新页。因此纸张方向、物理宽高、页面宿主和正文区域要一起核对。",{"type":60,"tag":78,"props":113,"children":115},{"id":114},"这个项目怎样把尺寸对齐",[116],{"type":66,"value":117},"这个项目怎样把尺寸对齐？",{"type":60,"tag":68,"props":119,"children":120},{},[121],{"type":66,"value":122},"模板里的长度可能使用 mm、cm、in、pt、pc。项目先统一换算成毫米，计算后再格式化回目标单位，并控制小数位。例如 1 in 是 25.4 mm，1 pt 是 25.4\u002F72 mm；直接取字符串中的数字相减，会把不同单位混在一起。",{"type":60,"tag":68,"props":124,"children":125},{},[126],{"type":66,"value":127},"当前产品使用 A4，因此先按横纵向统一纸张尺寸，再计算可打印区域，更新页面宿主宽度和正文高度。旧模板有两种保存正文高度的位置，同时存在就同时更新；模板分节中的页面也一起处理，避免只改顶层。",{"type":60,"tag":68,"props":129,"children":130},{},[131],{"type":66,"value":132},"非法或缺失长度需要明确处理，不能写回 NaN。这个做法也有适用前提：将来支持标签纸或自定义纸张时，不能继续强制改成 A4；正文高度调整为一页，也没有替长表、动态增长和重复页眉解决全部分页问题。",{"type":60,"tag":78,"props":134,"children":136},{"id":135},"浏览器有中文为什么导出仍然缺字",[137],{"type":66,"value":138},"浏览器有中文，为什么导出仍然缺字？",{"type":60,"tag":68,"props":140,"children":141},{},[142],{"type":66,"value":143},"浏览器可能从系统字体中找到汉字，导出引擎使用的却是自己的字体资源。页面显示正常，只能说明预览路径找到了字形。",{"type":60,"tag":68,"props":145,"children":146},{},[147],{"type":66,"value":148},"可选办法是给导出引擎准备所需字体，并让预览、导出和打印等待同一份加载结果。项目注册 Noto Sans CJK 作为默认字体，相关入口先等注册完成，避免用户很快点击导出时字体还没准备好。",{"type":60,"tag":68,"props":150,"children":151},{},[152],{"type":66,"value":153},"多个调用共享同一个 Promise，减少重复注册。但首次失败后缓存的仍是失败结果，重试还需另行设计。部署时也要检查字体是否进入产物、请求是否成功、字库是否含所需汉字，最终仍以 PDF 字形是否完整为准。",{"type":60,"tag":68,"props":155,"children":156},{},[157],{"type":66,"value":158},"几何用例可以固定横纵向、单位、边距、正文位置和分节，字体替身只能检查加载顺序。验收还要打开 PDF 看页数、边缘残片、中文、换行和打印比例，需要搜索复制时直接操作实际文件。本篇依据已有实现与打印复盘整理，没有重新导出业务报表。",{"type":60,"tag":78,"props":160,"children":162},{"id":161},"直接截图放进-pdf会不会简单一些",[163],{"type":66,"value":164},"直接截图放进 PDF，会不会简单一些？",{"type":60,"tag":68,"props":166,"children":167},{},[168],{"type":66,"value":169},"如果只需要外观快照，可以把画布转成图片再铺到纸张上。另一个画布原型使用的就是这条路，中文已经画在图片中，外观比较容易保持一致。",{"type":60,"tag":68,"props":171,"children":172},{},[173],{"type":66,"value":174},"代价是文字不能像原生文本一样选择和搜索，清晰度受输出像素与压缩影响。当前原型还是一张画布一页，没有动态分页。模板引擎则重新处理模板、数据和字体，更适合按报表需求检查分页，但也不能未经验证就假定所有内容都是矢量或可复制文本。",{"title":100,"searchDepth":176,"depth":176,"links":177},2,[178,179,180,181],{"id":80,"depth":176,"text":83},{"id":114,"depth":176,"text":117},{"id":135,"depth":176,"text":138},{"id":161,"depth":176,"text":164},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":183},"\u003Cpath fill=\"currentColor\" d=\"m10.828 12l4.95 4.95l-1.414 1.415L8 12l6.364-6.364l1.414 1.414z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":185},"\u003Cpath fill=\"currentColor\" d=\"M3 4h18v2H3zm0 7h12v2H3zm0 7h18v2H3z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":187},"\u003Cpath fill=\"currentColor\" d=\"m13.172 12l-4.95-4.95l1.414-1.413L16 12l-6.364 6.364l-1.414-1.415z\"\u002F>",{"left":4,"top":4,"width":189,"height":189,"rotate":4,"vFlip":6,"hFlip":6,"body":190},1024,"\u003Cpath fill=\"currentColor\" d=\"M768 832a128 128 0 0 1-128 128H192A128 128 0 0 1 64 832V384a128 128 0 0 1 128-128v64a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64z\"\u002F>\u003Cpath fill=\"currentColor\" d=\"M384 128a64 64 0 0 0-64 64v448a64 64 0 0 0 64 64h448a64 64 0 0 0 64-64V192a64 64 0 0 0-64-64zm0-64h448a128 128 0 0 1 128 128v448a128 128 0 0 1-128 128H384a128 128 0 0 1-128-128V192A128 128 0 0 1 384 64\"\u002F>"]