阅读 1295
monaco-editor:在你的网页中搞一个VsCode风格的代码编辑器~

monaco-editor:在你的网页中搞一个VsCode风格的代码编辑器~

前言

  • 公司有一个数据中台类的项目,因为之前技术栈比较老迭代不便等种种原因近期开始重构了,这个项目前辈们迭代了三年之久,可想重构起来的工作量[手动狗头],以前端技术栈是ng1.x + nodejs,重构选型react+hooks,因为是数据中台类型的项目,页面上写代码自然不可避免,本期重构的任务我负责的模块刚好有代码编辑器,ng1.x的项目用的是moaco-editor(微软开源的一款可嵌入网页中的代码编辑器,代码继承了vscode代码),为了风格更容易做到一致,所以我并不想更换代码编辑器的选型~

比较好用的 monaco-editor第三方包

  • ng1.x中并没有使用第三方包,而monaco-editor的官方文档读起来实在是...所以我果断打开npm搜了一波,还是有一些开源的包供我们使用的,介绍两个,亲测不错的 ①react-monaco-editor@monaco-editor/react

简单的聊一下 react-monaco-editor@monaco-editor/react的差异

  • 两者都是基于react + ts进行封装
  • react-monaco-editor看一下入口文件

image.png 我们可以看到,react-monaco-editor封装了 MonacoEditorMonacoDiffEditor帮我们处理了一些括号自动闭合、代码对比... 以及导出了一个 monaco的实例便于使用者定制。

  • @monaco-editor/react 同样看下入口文件 比上面丰富的一点试 @monaco-editor/react帮我们封装了几个声明周期的钩子,考虑再三我决定在项目中使用 @monaco-editor/react进行代码编辑器的定制化封装

image.png

monaco-editor 版本比较

  • 需要注意的是 monaco-editor 在0.25.1+代码会有不高亮的问题,解决办法:
    1. 自定义主题(后面会说)

    2. 使用webpack插件monaco-editor-webpack-plugin , create-react-app生成项目默认不暴露webpack.config.js , 需要我们使用第三方包或者执行npm eject暴露配置文件后修改配置 , 项目中我用的是craco.

            ① npm install monaco-editor-webpack-plugin
          //② 找到你的配置文件
          const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
          module.exports = {
            ...
            plugins: [
              new MonacoWebpackPlugin(['apex', 'azcli', 'bat', 'clojure', 'coffee', 'cpp', 'csharp', 'csp', 'css', 'dockerfile', 'fsharp', 'go', 'handlebars', 'html', 'ini', 'java', 'javascript', 'json', 'less', 'lua', 'markdown', 'msdax', 'mysql', 'objective', 'perl', 'pgsql', 'php', 'postiats', 'powerquery', 'powershell', 'pug', 'python', 'r', 'razor', 'redis', 'redshift', 'ruby', 'rust', 'sb', 'scheme', 'scss', 'shell', 'solidity', 'sql', 'st', 'swift', 'typescript', 'vb', 'xml', 'yaml'])
            ],
            ...
          };
      复制代码

基础用法

```js
import React, { Fragment } from "react";
import MonacoEditor from "@monaco-editor/react";
  const DpEditor = () => {
  
  const [code , setCode] = "SELECT user FROM acction_user"
  const options = {
    readOnly: true, //是否只读
    automaticLayout: true, //自动布局
    wordWrap: true, //折行展示
    ... // 配置项有很多,下面会贴配置项的官方文档
  };

  function onChangeHandle(value) {
    setCode(value)
  }

  function handleEditorWillMount(monaco) {
      // monaco 挂载后的钩子 参数为 monaco实例 , 在这里可以做一些定制化的操作
  }

  function handleEditorDidMount() {
    // 卸载后 这个钩子里可以做销毁monaco...操作
  }


  return (
    <Fragment>
      <div className="editor-container" style={{ height:"500" , width:"500" }}>
        <MonacoEditor
          loading={<div>loading...<div>}
          theme="vs"
          language={'sql'}
          value={code}
          options={options}
          onChange={onChangeHandle}
          beforeMount={handleEditorWillMount}
          onMount={handleEditorDidMount}
        />
      </div>
    </Fragment>
  );
};
export default DpEditor;
```
复制代码
  • 到这里我们可以看到一个拥有基础效果的代码编辑器了

image.png

丰富用法

  • 当然,大多数应用场景这点是完全不够的,我们需要一些定制化的内容

  • 自定义主题

    import React, { Fragment } from "react";
    import MonacoEditor from "@monaco-editor/react";
      const DpEditor = () => {
      
      const [code , setCode] = "SELECT user FROM acction_user"
      const options = {
        readOnly: true, //是否只读
        automaticLayout: true, //自动布局
        wordWrap: true, //折行展示
        ... // 配置项有很多,下面会贴配置项的官方文档
      };
    
      function onChangeHandle(value) {
        setCode(value)
      }
    
      function handleEditorWillMount(monaco) {
          // monaco 挂载后的钩子 参数为 monaco实例 , 在这里可以做一些定制化的操作
    +       defineTheme(monaco.editor);
      }
    
      function handleEditorDidMount() {
        // 卸载后 这个钩子里可以做销毁monaco...操作
      }
    
    +  function defineTheme( editor) {
    +    editor.defineTheme("dpLightTheme", {
    +      base: "vs-dark", // 基础主题
    +      inherit: true,
    +      rules: [...sqlTokenConfig], // 具体自定义内容
    +      colors: {
    +        "editor.background": "#313131", //编辑器背景色
    +        // 'editor.lineHighlightBorder': '#E7F2FD', // 编辑行边框色
    +      },
    +    });
    +  }
      return (
        <Fragment>
          <div className="editor-container" style={{ height:"500" , width:"500" }}>
            <MonacoEditor
              loading={<div>loading...<div>}
              theme="vs"
              language={'sql'}
              value={code}
              options={options}
              onChange={onChangeHandle}
              beforeMount={handleEditorWillMount}
              onMount={handleEditorDidMount}
            />
          </div>
        </Fragment>
      );
    };
    export default DpEditor;
    复制代码

    看下效果 , 代码颜色以及背景色已经使我们想要的颜色了

    image.png

  • 自定义代码提示

    import React, { Fragment } from "react";
    import MonacoEditor from "@monaco-editor/react";
      const DpEditor = () => {
      
      const [code , setCode] = "SELECT user FROM acction_user"
      const options = {
        readOnly: true, //是否只读
        automaticLayout: true, //自动布局
        wordWrap: true, //折行展示
        ... // 配置项有很多,下面会贴配置项的官方文档
      };

      function onChangeHandle(value) {
        setCode(value)
      }

      function handleEditorWillMount(monaco) {
          // monaco 挂载后的钩子 参数为 monaco实例 , 在这里可以做一些定制化的操作
            defineTheme(monaco.editor);
            customPrompt( monaco);
      }

      function handleEditorDidMount() {
        // 卸载后 这个钩子里可以做销毁monaco...操作
      }

      function defineTheme( editor) {
       editor.defineTheme("dpLightTheme", {
         base: "vs-dark", // 基础主题
          inherit: true,
          rules: [...sqlTokenConfig], // 具体自定义内容
          colors: {
            "editor.background": "#313131", //编辑器背景色
            // 'editor.lineHighlightBorder': '#E7F2FD', // 编辑行边框色
          },
        });
      }
      
     function customPrompt(monaco) {
    const suggestions = ["XID", "XML", "XOR", "YEAR", "YEAR_MONTH", "ZEROFILL", "我是自定义的"].map((item) => {
      return {
        insertText: item,
        kind: monaco.languages.CompletionItemKind.Function, // 对应提示图标的不同
        label: item,
      };
    });
    monaco.languages.registerCompletionItemProvider(language, {
      provideCompletionItems() {
        return {
          suggestions,
        };
      },
      quickSuggestions: true, // 默认提示关闭
      triggerCharacters: ["$", ".", "=", ":"], // 触发提示的字符 可以定义多个
    });
  }
      return (
        <Fragment>
          <div className="editor-container" style={{ height:"500" , width:"500" }}>
            <MonacoEditor
              loading={<div>loading...<div>}
              theme="vs"
              language={'sql'}
              value={code}
              options={options}
              onChange={onChangeHandle}
              beforeMount={handleEditorWillMount}
              onMount={handleEditorDidMount}
            />
          </div>
        </Fragment>
      );
    };
    export default DpEditor;
复制代码
  • 看下效果

image.png

  • monaco官方地址 感兴趣的话可以去读一下,有时间的话我会继续补存的.

-END-

文章分类
前端
文章标签