开发具有实时预览功能的Markdown编辑器

JavaScriptJavaScriptBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在这个项目中,我们将创建一个简单的基于网页的 Markdown 编辑器,它能在你输入时提供实时 HTML 预览。通过使用 Ace Editor、markedhighlight.js 等库,你将开发一个直观的编辑器,它不仅允许你用 Markdown 进行编写,还能在不同浏览器会话间保存数据,并在预览中突出显示代码片段。

👀 预览

Markdown 编辑器实时预览

🎯 任务

在这个项目中,你将学习:

  • 如何为编辑器和预览器设置 HTML 结构
  • 如何对编辑器和预览器进行样式设计以获得愉悦的用户体验
  • 如何实现编辑器初始化逻辑
  • 如何将 Markdown 解析为 HTML 并在预览器中显示
  • 如何在编辑器和预览器之间同步滚动

🏆 成果

完成这个项目后,你将能够:

  • 开发一个具有实时 HTML 预览功能的基于网页的 Markdown 编辑器
  • 利用 Ace Editor、markedhighlight.js 等库增强编辑器的功能
  • 实现跨浏览器会话的数据持久化
  • 在 Markdown 预览中提供代码语法高亮显示

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL javascript(("`JavaScript`")) -.-> javascript/BasicConceptsGroup(["`Basic Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/DOMManipulationGroup(["`DOM Manipulation`"]) javascript(("`JavaScript`")) -.-> javascript/ToolsandEnvironmentGroup(["`Tools and Environment`"]) javascript/BasicConceptsGroup -.-> javascript/functions("`Functions`") javascript/DOMManipulationGroup -.-> javascript/dom_select("`DOM Selection`") javascript/DOMManipulationGroup -.-> javascript/dom_manip("`DOM Manipulation`") javascript/DOMManipulationGroup -.-> javascript/event_handle("`Event Handling`") javascript/DOMManipulationGroup -.-> javascript/dom_traverse("`DOM Traversal`") javascript/ToolsandEnvironmentGroup -.-> javascript/web_storage("`Web Storage`") subgraph Lab Skills javascript/functions -.-> lab-445690{{"`开发具有实时预览功能的Markdown编辑器`"}} javascript/dom_select -.-> lab-445690{{"`开发具有实时预览功能的Markdown编辑器`"}} javascript/dom_manip -.-> lab-445690{{"`开发具有实时预览功能的Markdown编辑器`"}} javascript/event_handle -.-> lab-445690{{"`开发具有实时预览功能的Markdown编辑器`"}} javascript/dom_traverse -.-> lab-445690{{"`开发具有实时预览功能的Markdown编辑器`"}} javascript/web_storage -.-> lab-445690{{"`开发具有实时预览功能的Markdown编辑器`"}} end

设置 HTML 结构

要求

  • 熟悉基本的 HTML 标签。

功能

  • 为编辑器和预览器奠定基础。

index.html 中,为编辑器和预览器设置基本的 HTML 结构。为编辑器和预览窗格都留出空间。

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>markdown editor</title>

    <!-- 导入 CSS 文件 -->
    <link rel="stylesheet" href="libs/bootstrap/css/bootstrap.min.css" />
    <link rel="stylesheet" href="libs/highlightjs/default.min.css" />
    <link rel="stylesheet" href="libs/highlightjs/monokai_sublime.min.css" />
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <!-- markdown 编辑器 div -->
        <div class="col-md-6" id="md-editor"></div>
        <!-- markdown 预览框 div -->
        <div class="col-md-6" id="md-viewer"></div>
      </div>
    </div>
    <!-- 导入 JavaScript 文件 -->
    <script src="libs/jquery.min.js"></script>
    <script src="libs/bootstrap/js/bootstrap.min.js"></script>
    <script src="libs/ace/ace.js"></script>
    <script src="libs/marked.min.js"></script>
    <script src="libs/highlightjs/highlight.min.js"></script>
    <script src="main.js"></script>
  </body>
</html>
✨ 查看解决方案并练习

为编辑器和预览器设置样式

要求

  • 具备基本的 CSS 知识。

功能

  • 为编辑器和预览器设置样式,以提供愉悦的用户体验。

将提供的样式插入到 style.css 中。这将确保编辑器和预览器都能正确设置样式,并且各自占据屏幕的一半。

/* style.css */

/* 编辑区域 */
#md-editor {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  font-size: 16px;
}

/* 预览区域 */
#md-viewer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 50%;
  overflow-y: scroll;
}

这段 CSS 确保编辑器和预览器各自占据屏幕的一半,并并排显示。

✨ 查看解决方案并练习

实现编辑器初始化

要求

  • 对 JavaScript 有基本的了解。

功能

  • 使用所需设置来初始化 Ace Editor。

main.js 中开始编写编辑器初始化逻辑。

/* main.js */

/**
 * 初始化编辑器
 *
 */
function initEditor() {
  // 初始化编辑器
  var editor = ace.edit("md-editor");

  editor.setTheme("ace/theme/monokai"); // 设置主题样式
  editor.getSession().setMode("ace/mode/markdown"); // 设置编辑器模式
  editor.getSession().setTabSize(4); // 将制表符设置为 4 个空格
  editor.getSession().setUseWrapMode(true); // 启用自动换行

  // 从本地存储加载数据
  editor.setValue(localStorage.localData || "");
}
✨ 查看解决方案并练习

实现 Markdown 解析

要求

  • 熟悉 JavaScript 和 jQuery。

功能

  • 将 Markdown 转换为 HTML。
  • 在预览器中显示 HTML。
/**
 * 解析 Markdown
 *
 * @params {object} editor - 编辑器实例
 * @return {object} - 预览框
 */
function parseMarkdown(editor) {
  var viewer = $("#md-viewer"); // 文档预览框
  var data = editor.getValue(); // 获取编辑器数据

  // 将数据保存到本地存储
  localStorage.localData = data;
  // 解析 Markdown
  data = marked(data);
  viewer.html(data);

  // 高亮显示 Markdown 文档中的代码
  $("pre > code", viewer).each(function () {
    hljs.highlightBlock(this);
  });

  // 返回预览框
  return viewer;
}
✨ 查看解决方案并练习

同步编辑器和预览器之间的滚动

要求

  • 了解 JavaScript 事件。

功能

  • 同步编辑器和预览器的滚动。
/*
 * 控制滚动条
 * 同步编辑器和预览框之间的滚动
 *
 * @params {object} editor - 编辑器实例
 * @params {object} viewer - 预览框
 */
function fixScrollBar(editor, viewer) {
  var session = editor.getSession();

  // 默认为滚动到第一行
  session.setScrollTop(0);

  // 为编辑器绑定滚动事件
  session.on("changeScrollTop", function () {
    var sTop = session.getScrollTop();
    // 设置预览框的滚动条
    viewer.scrollTop(sTop);
  });

  // 为预览框设置滚动事件
  viewer.on("scroll", function () {
    var sTop = viewer.scrollTop();
    // 设置编辑器的滚动条
    session.setScrollTop(sTop);
  });
}
✨ 查看解决方案并练习

整合所有功能并初始化编辑器

要求

  • 掌握 JavaScript 中的函数调用。

功能

  • 将之前的所有步骤合并到一个统一的代码中。
  • 初始化编辑器并应用所有功能。
/* main.js */

initEditor();

/**
 * 初始化编辑器
 *
 */
function initEditor() {
  // 初始化编辑器
  var editor = ace.edit("md-editor");

  editor.setTheme("ace/theme/monokai"); // 设置主题样式
  editor.getSession().setMode("ace/mode/markdown"); // 设置编辑器模式
  editor.getSession().setTabSize(4); // 将制表符设置为 4 个空格
  editor.getSession().setUseWrapMode(true); // 启用自动换行

  // 从本地存储加载数据
  editor.setValue(localStorage.localData || "");

  // 解析从本地存储加载的数据
  var viewer = parseMarkdown(editor);
  // 控制滚动条
  fixScrollBar(editor, viewer);

  // 实时 Markdown 解析
  editor.getSession().on("change", function (e) {
    parseMarkdown(editor);
  });
}
✨ 查看解决方案并练习

运行项目

  • 在网页浏览器中打开 index.html
    open web
  • 以查看和测试你的 Markdown 编辑器。
  • 页面效果如下:
    Markdown editor page preview
✨ 查看解决方案并练习

总结

恭喜你!你刚刚创建了一个具有实时预览功能的基于网络的 Markdown 编辑器。现在,你可以编写 Markdown 内容,查看其实时 HTML 表示形式,甚至还能突出显示其中的代码片段。请记住,由于使用了 localStorage,你编写的内容将在不同的浏览器会话中持久保存。编码愉快!

您可能感兴趣的其他 JavaScript 教程