[{"data":1,"prerenderedAt":222},["ShallowReactive",2],{"quirekit-doc:\u002Fbuild\u002Ffiles":3},{"id":4,"title":5,"body":6,"description":210,"extension":211,"keywords":212,"locale":213,"meta":214,"navigation":215,"order":216,"path":217,"section":218,"seo":219,"stem":220,"__hash__":221},"docs\u002Fbuild\u002Ffiles.zh-CN.md","保存与打开文档",{"type":7,"value":8,"toc":202},"minimark",[9,13,18,56,67,78,82,85,88,94,98,101,118,128,135,139,142,148,152,166,181,184,198],[10,11,12],"p",{},"编辑器负责修改内容，应用负责把内容保存到哪里。本章先实现产品自己的 JSON 备份，再解释打开文件时的校验，以及 DOCX 与备份的区别。",[14,15,17],"h2",{"id":16},"_1-在保存按钮中读取内容","1. 在保存按钮中读取内容",[19,20,26],"pre",{"className":21,"code":22,"filename":23,"language":24,"meta":25,"style":25},"language-ts shiki shiki-themes github-light github-light github-dark","const content = editor.getJSON()\n","保存时读取 JSON","ts","",[27,28,29],"code",{"__ignoreMap":25},[30,31,34,38,42,45,49,53],"span",{"class":32,"line":33},"line",1,[30,35,37],{"class":36},"sDD9d","const",[30,39,41],{"class":40},"sUNQB"," content",[30,43,44],{"class":36}," =",[30,46,48],{"class":47},"sVPnS"," editor.",[30,50,52],{"class":51},"sgQzM","getJSON",[30,54,55],{"class":47},"()\n",[10,57,58,59,62,63,66],{},"返回值包含节点、属性和文字格式。你可以把它交给数据库、接口或浏览器存储。保存时另外记录版本和模型名，例如 ",[27,60,61],{},"version: 1","、",[27,64,65],{},"model: 'generic-v1'","，以后才能识别需要迁移的旧文件。",[10,68,69,70,73,74,77],{},"完整示例的 ",[27,71,72],{},"files\u002Frepository.ts"," 把备份写到 ",[27,75,76],{},"localStorage","。这是浏览器本地存储，适合演示或本地草稿；跨设备同步需要你自己的服务端。",[14,79,81],{"id":80},"_2-保存成功时确认保存的是哪一版","2. 保存成功时确认保存的是哪一版",[10,83,84],{},"用户可能在等待保存时继续输入。开始保存时记录当时的文档，只有当前内容仍是这一版，才能清除“有未保存修改”的提示。",[10,86,87],{},"保存失败时保留正文和未保存状态，显示错误以便重试。浏览器存储也可能因空间不足而失败，因此必须等实际写入成功后再显示成功。",[10,89,90,93],{},[27,91,92],{},"session.ts"," 负责协调这些状态，正文仍由 Editor 保存，不需要另外复制成一份可编辑的 Vue 数据。",[14,95,97],{"id":96},"_3-先校验再恢复","3. 先校验，再恢复",[10,99,100],{},"收到文件后先检查备份版本和模型，再用当前 Schema 检查节点、标记、属性和子内容。全部通过后，再替换编辑器中的文档：",[19,102,105],{"className":21,"code":103,"filename":104,"language":24,"meta":25,"style":25},"editor.commands.replaceDocument(content)\n","恢复已验证的完整文档",[27,106,107],{"__ignoreMap":25},[30,108,109,112,115],{"class":32,"line":33},[30,110,111],{"class":47},"editor.commands.",[30,113,114],{"class":51},"replaceDocument",[30,116,117],{"class":47},"(content)\n",[10,119,120,123,124,127],{},[27,121,122],{},"replaceDocument()"," 用于完整文件恢复，也会恢复文档顶层属性；普通正文替换可以使用 ",[27,125,126],{},"setContent()","。检查失败时保留原文件和当前草稿，避免把不认识的节点丢掉以后又覆盖备份。",[10,129,130,131,134],{},"完整验证实现位于 ",[27,132,133],{},"files\u002Fbackup.ts","。打开文件前，示例会要求先保存当前修改。",[14,136,138],{"id":137},"_4-避免迟到的加载覆盖新编辑","4. 避免迟到的加载覆盖新编辑",[10,140,141],{},"读取文件和格式转换可能是异步的。等结果返回时，用户可能已经打开别的文档、继续输入、切换到只读，或离开页面。",[10,143,144,145,147],{},"提交前检查当前实例、这次加载任务以及文档是否仍与开始时一致。失效的结果不再提交。示例的 ",[27,146,92],{}," 在一个地方处理这些检查，避免每个文件按钮各自遗漏一种情况。",[14,149,151],{"id":150},"_5-接入-docx","5. 接入 DOCX",[10,153,154,155,158,159,162,163,165],{},"JSON 备份保存你的产品模型；DOCX 是另一种文件格式，需要对应的转换规则。Word 工作区通过 ",[27,156,157],{},"@quirekit\u002Fclassic-docx\u002Fdocx"," 的公开入口按需加载转换能力，",[27,160,161],{},"files\u002Fdocx.ts"," 负责字节和转换结果，",[27,164,92],{}," 负责决定是否提交。",[10,167,168,169,172,173,176,177,180],{},"自建工作区可以复用这些转换入口；使用 Classic 产品时，可直接安装 ",[27,170,171],{},"createClassicWordDocxPlugin()","，通过 ",[27,174,175],{},"instance.importDocument()"," 和 ",[27,178,179],{},"exportDocument()"," 调用文件服务。",[10,182,183],{},"转换可能产生不支持内容的诊断，界面应保留并展示它。图片还需要媒体存储，不能只保存 JSON 中的引用就认为图片文件也已经保存。",[10,185,186,187,192,193,197],{},"完整文件按用途收在",[188,189,191],"a",{"href":190},"\u002Fbuild\u002Freference","工程参考","。下一章说明",[188,194,196],{"href":195},"\u002Fbuild\u002Fresources","图片、字体与其他产品能力","。",[199,200,201],"style",{},"html pre.shiki code .sDD9d, html code.shiki .sDD9d{--shiki-default:#D73A49;--shiki-light:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sUNQB, html code.shiki .sUNQB{--shiki-default:#005CC5;--shiki-light:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVPnS, html code.shiki .sVPnS{--shiki-default:#24292E;--shiki-light:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sgQzM, html code.shiki .sgQzM{--shiki-default:#6F42C1;--shiki-light:#6F42C1;--shiki-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":25,"searchDepth":203,"depth":203,"links":204},2,[205,206,207,208,209],{"id":16,"depth":203,"text":17},{"id":80,"depth":203,"text":81},{"id":96,"depth":203,"text":97},{"id":137,"depth":203,"text":138},{"id":150,"depth":203,"text":151},"先保存 JSON，再加入校验、异步状态和 DOCX 文件转换。","md",null,"zh-CN",{},true,7,"\u002Fbuild\u002Ffiles","构建产品",{"title":5,"description":210},"build\u002Ffiles.zh-CN","wPZfZbD30eFjGL9UBZFHEFXa4EiMw-8u_CeZtu6gFyQ",1793045209086]