构建支持本地草稿和下载的 Markdown 写作应用

使用 RichTextEditor 构建的在线写作应用 RichMarkdown

构建一个浏览器应用,让用户以可视化方式写作,将 Markdown 草稿保存到本地,并下载 .md 文件。此工作流适用于文档草稿、README 文件或个人笔记。

要体验完整的在线示例,请打开 RichMarkdown。它使用 RichTextEditor,并提供本地笔记、研究资料剪藏和多种导出选项。该产品可免费使用;在自己的应用中使用编辑器时,仍需单独考虑编辑器的授权。

先准备好可用的编辑器

下载编辑器,并通过网站提供其 richtexteditor 文件夹。通过本地 Web 服务器运行页面,不要直接打开 file: URL。创建实例前,先加载核心和插件。快速入门介绍了各框架的具体配置方法。

添加草稿保存和下载操作

下面的完整页面会创建名为 editor 的编辑器、带有 id="download" 的按钮,以及带有 id="save-status" 的状态元素。为每个文档使用不同且固定的键。

<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css">
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>
<div id="editor"></div>
<button id="download" type="button">Download .md</button>
<p id="save-status" role="status"></p>
<script>
const editor = new RichTextEditor("#editor");
const status = document.getElementById("save-status");
const key = "my-markdown-draft";
let saved = "";
try { saved = localStorage.getItem(key) || ""; }
catch { status.textContent = "Browser storage is unavailable. Download a copy."; }
editor.fromMarkdown(saved || "# Untitled\n\nStart writing.");

function saveDraft() {
  try {
    localStorage.setItem(key, editor.toMarkdown());
    status.textContent = "Saved in this browser.";
  } catch {
    status.textContent = "Draft could not be saved. Download a copy.";
  }
}
let timer;
editor.attachEvent("change", function () {
  clearTimeout(timer);
  timer = setTimeout(saveDraft, 300);
});
window.addEventListener("pagehide", saveDraft);

document.getElementById("download").addEventListener("click", function () {
  const blob = new Blob([editor.toMarkdown()], {
    type: "text/markdown;charset=utf-8"
  });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = "document.md";
  document.body.appendChild(link);
  link.click();
  link.remove();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
});
</script>

确定 Markdown 必须保留的内容

在决定仅使用 Markdown 保存文档之前,先用实际文档进行测试。标题、列表、链接、引用和围栏代码块都有对应的 Markdown 表示方式。合并的表格单元格、批注和任意字体样式则无法准确转换为普通 Markdown。如果这些细节很重要,还应保留 HTML 或结构化 JSON。

代码块的语言标记用于描述其内容,不会执行、编译或验证代码。JavaScript、TypeScript、PHP 和 C# 示例应作为文本保留在文档中。

本地草稿只是便捷功能

  • localStorage 中的数据属于当前浏览器和源。它不是备份、加密存储或跨设备同步机制。
  • 清除网站数据会删除草稿。请提供下载操作,并在编辑器附近说明这一点。
  • 处理多个文档时,使用独立的键和文档列表。文档数量较多时,可能需要 IndexedDB。
  • 团队使用时,应采用需要身份验证的服务器存储,并处理编辑冲突。共用一个本地键并不能实现协作。

处理客户文档前的准备

对服务器端的每次读写都进行授权检查。将提交的 Markdown 视为不可信输入。如果服务器将其转换为 HTML,应根据 HTML 的展示位置,选择适当的 Markdown 渲染器和 HTML 净化策略。浏览器预览不能替代服务器端验证。

将图片文件单独保存,并存储稳定的 URL。Markdown 文件不会自动包含其引用的图片。请参阅保存包含图片的富文本。

检查工作流

  1. 输入标题和列表,然后等待保存成功的提示。
  2. 重新加载页面,确认草稿已恢复。
  3. 添加代码块,下载文件,并在 Markdown 阅读器中打开。
  4. 检查语言标记、缩进、链接和图片。
  5. 禁用浏览器存储,确认仍可下载文件。

接下来可参阅将 Word 和 Google Docs 文档转换为 Markdown、交互式 Markdown 演示和必填内容验证。

延伸阅读