Monaco Editor 入门指南

⚠️ 注意:本教程已过时。本教程的正确食用方法是从 GitHub monaco-editor-demos 上直接下载代码,然后点击 index.html 直接查看 Demo 及 源码。本文中描述的构建方法可能已不适用(更新于 2024.04)

GitHub项目链接:monaco-editor-demos

在学习 Monaco Editor 的过程中,我发现网络上的中文教程很少。为了填补这部分空白,我决定写一份入门教程,帮助初学者快速熟悉 Monaco Editor。通过阅读本文,你可以了解以下内容:

  1. 如何安装
  2. 如何搭建
  3. 如何调用常用 API
  4. 如何寻找学习资源

安装

新建项目文件夹,打开它:

$ mkdir my-application
$ cd my-application

确保你已经下载了 npm,然后安装 Monaco Editor:

$ npm install monaco-editor

搭建

本文提供了搭建 Monaco Editor 的一种方法,此方法的特点是能够兼容文件系统。如果你希望为后续应用添加文件管理系统,那么参考本文的搭建流程可以避免不必要的踩坑。添加文件系统的具体方法参见 monaco-speech-editor

有两种搭建方式可选:

方式一:直接从GitHub仓库下载。

方式二:手动搭建。

下面介绍了手动搭建的流程。

首先,在项目文件夹 my-application 下,新建一个名为 base 的文件夹。然后在该文件夹下新建 index.html, app.js, style.css:

$ mkdir base
$ cd base
$ touch index.html app.js style.css

在本地编辑器打开 index.html,输入:

<!DOCTYPE html>
<html>

<head>
    <title>Monaco Editor Demo</title>
    <link rel="stylesheet" href="./style.css">
    <script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
    <script src="./app.js"></script>
</head>

<body>
    <div id="header">基础版 Monaco Editor</div>
    <div id="root"></div>
</body>

</html>

打开 app.js,输入:

require.config({ paths: { 'vs': '../node_modules/monaco-editor/min/vs' } });
require(['vs/editor/editor.main'], function () {

    // 初始化变量
    var fileCounter = 0;
    var editorArray = [];
    var defaultCode = [
        'function helloWorld() {',
        '   console.log("Hello world!");',
        '}'
    ].join('\n');

    // 定义编辑器主题
    monaco.editor.defineTheme('myTheme', {
        base: 'vs',
        inherit: true,
        rules: [{ background: 'EDF9FA' }],
    });
    monaco.editor.setTheme('myTheme');

    // 新建一个编辑器
    function newEditor(container_id, code, language) {
        var model = monaco.editor.createModel(code, language);
        var editor = monaco.editor.create(document.getElementById(container_id), {
            model: model,
        });
        editorArray.push(editor);
        return editor;
    }

    // 新建一个 div
    function addNewEditor(code, language) {
        var new_container = document.createElement("DIV");
        new_container.id = "container-" + fileCounter.toString(10);
        new_container.className = "container";
        document.getElementById("root").appendChild(new_container);
        newEditor(new_container.id, code, language);
        fileCounter += 1;
    }

    addNewEditor(defaultCode, 'javascript');

});

打开 style.css,输入:

body {
  font-family: "Source Han Sans", "San Francisco", "PingFang SC", "Hiragino Sans GB", "Droid Sans Fallback", "Microsoft YaHei", sans-serif;
  transition: background-color .2s;
}

#header {
  position: fixed;
  top: 0;
  left: 0;
  height: 50px;
  right: 0;
  
  background-color: #333;
  color: #fff;
  font-size: 20px;
  
  line-height: 50px;
  display: inline-block;
  vertical-align: middle;
  padding-left: 15px;

  overflow: hidden;
  z-index: 0;
}

.container {
  position: fixed;
  top: 50px;
  left: 0;
  height: calc(100vh - 50px);
  right: 0;

  margin: 0 auto;
  display: block;

  transition: 0.2s;
  overflow: hidden;
  z-index: 0;
}

最终搭建效果如下:

常用 API

Monaco Editor 提供了极为丰富的 API,为了帮助初学者快速入门,本文提供了一些 API 调用范例。点击以下文段中的本例 Demo 链接,即可查看代码。

(一)获取编辑器内容

获取编辑器内容的 API 如下:

ITextModel.getValue()

其中,ITextModel 是 Monaco Editor 中的一种特殊的数据类型。如果你用 monaco.editor.create() 函数搭建编辑器。那么 ITextModel 其实就是该函数的返回值。

Demo 效果图:

参见:

(二)实时获取光标所在行号和列号

获取光标所在行号和列号的 API 如下:

ITextModel.getPosition().lineNumber
ITextModel.getPosition().column

如果需要实时获取,即在每次光标移动时更新行号和列号,还需要加一个监听器:

ITextModel.onDidChangeCursorPosition((e) => {
    // some codes here.
});

Demo 效果图:

参见:

(三)语法高亮

设置语法高亮的 API 如下:

setModelLanguage(model: ITextModel, languageId: string)

Demo 效果图:

参见:

学习资源

授人以鱼不如授人以渔,以下是几个比较重要的资料来源。Monaco Editor 的中文资源很少,因此以下都是英文资源:

链接 说明
官方代码仓库的 issue 区 源代码仓库的 issue 区下,有很多使用者的提问。Monaco editor 的开发人员回复了其中很多问题。因此,如果你在使用中遇到麻烦,可以尝试在 issue 区用关键字搜索一下。
官方代码仓库的 used by 区 Used by 区的作用是寻找使用了本框架的其他开源仓库。如果有毅力一直翻下去,你很可能会找到和你用该框架做相似实现的仓库。那么你就可以借鉴他的代码了。
官方 demo 仓库 官方 demo 仓库是个好东西,这是一切开始的地方。跑一跑官方demo,很多事就不言自明了,省了翻阅文档的时间。
Playground Playground 和 官方 demo 仓库作用差不多,但它是部署在网络上的。可以先在 playground 里试验以后,明确自己需要这个功能了,然后再在本地搭建。
API 文档 鉴于 Monaco Editor 是一个仍在更新的项目,API 文档 的内容也未必完全正确。但它确实是收录 API 最全面的地方。如果你需要实现的功能比较偏门,找不到任何 demo 和教程,那么自己查 API 文档往往是最终的办法。
Stackoverflow Stackoverflow 也有很多关于 Monaco Editor 的问答。

推荐阅读

如果你对本项目感兴趣,那么你可能同样对 Monaco Speech Editor 感兴趣。

Note: Monaco Speech Editor 是笔者编写的一款适用于视障人群的在线代码编辑器。它提供丰富的语音辅助功能,可以精准地定位并朗读用户指定内容。并且,它还提供多种语音模式,比如字符模式、音乐模式、全局模式。这些模式可以根据用户在不同编程阶段的不同需求,提供差异化的语音内容输出。此外,它内置供全盲者使用的操作界面,从而使全盲者无需使用电脑屏幕和鼠标,也能正常使用本编辑器。

Monaco Speech Editor 中集成了大量 Monaco Editor 的 API。并且在细节上做了很多优化。本项目是 Monaco Speech Editor 的子项目,是把 Monaco Speech Editor 中可以通用的部分代码抽取出来形成的。如果想尝试 Monaco Editor 的更多功能,欢迎 star, clone 和 fork。