如何使用Codemirror建立一个代码编辑器

489 阅读4分钟

在线代码教程网站带来了对实时代码编辑器的需求。这些编辑器的目的是描绘代码片段或为代码片段添加一些增强功能。在线代码编辑器也作为远程工作空间和团队工作工具。 有几个网站使用代码编辑器,其中最受欢迎的是codepen 。还有其他值得一提的,如w3schooljs fiddle

在这篇文章中,我们将围绕CodeMirror展开。CodeMirror就是我们所说的用JavaScript实现的flexible 文本编辑器,用于浏览器编辑代码。我们将讨论codemirror的几种语言模式和用于更高级的编辑功能的附加组件。

它是Mozilla的FirefoxIOS的SafariGoogle的Chrome的开发工具中使用的编辑器。本教程将指导你如何使用code mirror独特的API建立你的代码编辑器。

目标

在本指南中,我们将使用codemirror的API建立一个代码编辑器。在本教程结束时,我们将有一个功能性的代码编辑器来运行HTMLCSSJavaScript

它还将具有诸如代码自动完成、快速格式等功能。通过split.js,我们的编辑器将有一个分割的、可调整的屏幕,在编辑器和iframe之间显示。

开始使用

为了开始,我们需要导入codemirror的JavaScript和CSS文件。我们下载了这些文件,并存储在这里的GitHub仓库中。为了使事情更简单,我们建议将这些文件下载到你的本地存储。

创建导航条

我们将创建一个简单的前端,其中包括运行等按钮和一个包含我们的格式和评论功能的下拉列表。为了实现这一点,我们将利用bootstrap 5 ,这将有助于页面的风格化。

为了开始,我们初始化我们的HTML模板,添加我们的个人CSS,bootstrap JS,以及使用内容交付网络(CDN)的CSS文件。

<html lang="en">
  <head>
    <title>Code-Editor</title>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
    />
  </head>
  <body></body>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</html>

接下来,我们将创建一个包含上述功能的导航条。我们将首先在我们的正文部分添加一个nav 标签,然后是一个div。

之后,我们将在div中添加一个无序列表标签(ul ),同时在run 中添加一个有序列表标签(li )。这就是导航条的基本标签。

导航条的理想设计如下所示。

<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <ul class="nav navbar-nav">
      <li><a class="btn" id="run-btn">Run</a></li>
      <li class="nav-item dropdown">
        <a class="btn dropdown-toggle" type="button" data-toggle="dropdown"
          >Dropdown Example <span class="caret"></span
        ></a>
        <ul class="dropdown-menu">
          <li><a href="javascript:autoFormatSelection()">Format</a></li>
          <li><a href="javascript:commentSelection(true)">Comment</a></li>
          <li><a href="javascript:commentSelection(false)">Uncomment</a></li>
        </ul>
      </li>
    </ul>
  </div>
</nav>

如果实施得当,我们应该看到我们的导航条如下图所示。

nav

添加文本编辑器和iframe显示

这一部分涉及添加一个并排的编辑器和iframe显示。我们将在split.js的帮助下,使用一个可调整的调整器将它们分开。我们将添加codemirrors的CSS和JS文件,split.js文件与内容交付网络。

<link rel="stylesheet" href="codemirror.css" />
<script src="codemirror.js"></script>
<script src="https://unpkg.com/split.js/dist/split.min.js"></script>

注意:我们对Codemirror的CSS做了一些轻微的修改,以获得我们想要的结果。

然后我们创建一个容器div ,接着在容器内创建两个独立的div 。其中一个div 是用于编辑器,另一个用于iframe显示。对于分割功能,我们将为其创建一个脚本标签。

下面是一个实现的例子。

<div class="editor">
  <div id="resizeMe" class="code a">
    <div class="html-code"></div>
  </div>
  <div class="code pa">
    <iframe id="preview-window"></iframe>
  </div>
</div>
<script>
  Split([".a", ".pa"]);
</script>

.a 和 是编辑器和iframe显示的类名。.pa

总的来说,我们应该有如下所示的布局。

editor

添加主要的编辑器功能

接下来,我们将使编辑器兼容JavaScript、CSS和HTML。我们还将添加自动完成和格式化功能。

让我们开始吧。我们需要将JavascriptHTMLCSS 的JavaScript文件导入我们的代码,如下图所示。

<script src="xml.js"></script>
<script src="javascript.js"></script>
<script src="css.js"></script>
<script src="htmlmixed.js"></script>

我们将创建一个脚本标签,这是项目的基本部分。根据文档,我们要使用.getValue() ,而不是.value()

JavaScript的代码如下所示。

var htmlEditor = CodeMirror(
  document.querySelector(".editor .code .html-code"),
  {
    mode: "htmlmixed",
    tabSize: 4,
    lineNumbers: true,
    extraKeys: { "Ctrl-Space": "autocomplete" },
  }
);
CodeMirror.commands["selectAll"](htmlEditor);

function getSelectRange() {
  return { from: htmlEditor.getCursor(true), to: htmlEditor.getCursor(false) };
}

function autoFormatSelection() {
  var range = getSelectRange();
  htmlEditor.autoFormatRange(range.from, range.to);
}

function commentSelection(isComment) {
  var range = getSelectRange(),
    selStart = htmlEditor.getCursor("start");
  htmlEditor.commentRange(isComment, range.from, range.to);
  htmlEditor.setSelection(selStart, htmlEditor.getCursor("end"));
}
document.querySelector("#run-btn").addEventListener("click", function () {
  let htmlCode = htmlEditor.getValue();
  let previewWindow =
    document.querySelector("#preview-window").contentWindow.document;
  previewWindow.open();
  previewWindow.write(htmlCode);
  previewWindow.close();
});

.querySelector() 给出文档中第一个匹配给定CSS选择器的元素。

对于auto-compelete 功能、commentformat 功能,我们将导入它们各自的JavaScript和CSS文件,如下所示。

<link rel="stylesheet" href="show-hint.css" />
<script src="formatting.js"></script>
<script src="show-hint.js"></script>
<script src="xml-hint.js"></script>
<script src="html-hint.js"></script>

文件中的最终代码应该是这样的。

<html lang="en">
  <head>
    <title>Code-Editor</title>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="codemirror.css" />
    <link rel="stylesheet" href="show-hint.css" />
    <link
      rel="stylesheet"
      href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
    />
    <link rel="stylesheet" href="index.css" />
  </head>

  <body>
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <ul class="nav navbar-nav">
          <li><a class="btn" id="run-btn">Run</a></li>
          <li class="nav-item dropdown">
            <a class="btn dropdown-toggle" type="button" data-toggle="dropdown"
              >Options <span class="caret"></span
            ></a>
            <ul class="dropdown-menu">
              <li><a href="javascript:autoFormatSelection()">Format</a></li>
              <li><a href="javascript:commentSelection(true)">Comment</a></li>
              <li>
                <a href="javascript:commentSelection(false)">Uncomment</a>
              </li>
            </ul>
          </li>
        </ul>
      </div>
    </nav>
    <div class="editor">
      <div id="resizeMe" class="code a">
        <div class="html-code"></div>
      </div>
      <div class="code pa">
        <iframe id="preview-window"></iframe>
      </div>
    </div>
  </body>
  <script src="codemirror.js"></script>
  <script src="formatting.js"></script>
  <script src="show-hint.js"></script>
  <script src="xml-hint.js"></script>
  <script src="html-hint.js"></script>
  <script src="xml.js"></script>
  <script src="javascript.js"></script>
  <script src="css.js"></script>
  <script src="htmlmixed.js"></script>
  <script src="https://unpkg.com/split.js/dist/split.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
  <script>
    Split([".a", ".pa"]);
    var htmlEditor = CodeMirror(
      document.querySelector(".editor .code .html-code"),
      {
        mode: "htmlmixed",
        tabSize: 4,
        lineNumbers: true,
        extraKeys: { "Ctrl-Space": "autocomplete" },
      }
    );
    CodeMirror.commands["selectAll"](htmlEditor);

    function getSelectedRange() {
      return {
        from: htmlEditor.getCursor(true),
        to: htmlEditor.getCursor(false),
      };
    }

    function autoFormatSelection() {
      var range = getSelectedRange();
      htmlEditor.autoFormatRange(range.from, range.to);
    }

    function commentSelection(isComment) {
      var range = getSelectedRange(),
        selStart = htmlEditor.getCursor("start");
      htmlEditor.commentRange(isComment, range.from, range.to);
      htmlEditor.setSelection(selStart, htmlEditor.getCursor("end"));
    }
    document.querySelector("#run-btn").addEventListener("click", function () {
      let htmlCode = htmlEditor.getValue();
      let previewWindow =
        document.querySelector("#preview-window").contentWindow.document;
      previewWindow.open();
      previewWindow.write(htmlCode);
      previewWindow.close();
    });
  </script>
</html>

如果实施得当,我们应该有以下结果。

main editor

main editor 2

结论

总之,我们学会了如何创建一个兼容HTML、CSS和JavaScript的编辑器。我们添加了一个HTML代码格式功能、自动完成功能、使用split.js的可调分屏。

我们将所有这些组件集合在一起,使用codemirror建立了一个响应式的代码编辑器。