monaco-editor 使用總結


 

monaco-editor 介紹

微軟之前有個項目叫做 Monaco Workbench,后來這個項目變成了VSCode,而 Monaco Editor 就是從這個項目中成長出來的一個web編輯器,他們很大一部分的代碼(monaco-editor-core)都是共用的,所以monaco和VSCode在編輯代碼,交互以及UI上幾乎是一摸一樣的,有點不同的是,兩者的平台不一樣,monaco基於瀏覽器,而VSCode基於electron,所以功能上VSCode更加健全,並且性能比較強大。

簡單來講,monaco-editor 是一個瀏覽器版本的 vscode。目前很多瀏覽器上的 "雲編輯器" 都是基於 monaco-editor 來做的。

安裝引入

安裝

tnpm install monaco-editor

頁面注冊使用

import * as monaco from 'monaco-editor';
import React, { useRef, useEffect } from 'react';

const CodeEditor: React.FC = () => {
  const editorRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (editorRef.current) {
      const editorIns = monaco.editor.create(editorRef.current, {
        language: 'sql',
        value,
        folding: true,
        theme: 'vs',
        scrollbar: {
          verticalScrollbarSize: 8,
          horizontalScrollbarSize: 8,
        },
        minimap: {
          enabled: withMiniMap,
        },
        formatOnPaste: true,
        renderValidationDecorations: 'on',
      });
    }
  }, [editorRef]);
  return <div ref={editorRef}></div>;
};

monaco-editor-webpack-plugin

在 monaco-editor 中需要處理 ts、html、json等語言時需要單獨的引入相應的 worker 。當我們使用 webpack 來作為構建工具的時候會不是很方便,這個時候可以通過 monaco-editor-webpack-plugin 來幫助我們處理這些問題,它可以用來做:

  1. 自動注入getWorkerUrl全局變量;
  2. 處理worker的編譯配置;
  3. 自動引入控件和語言包。

相關功能

編輯器適配屏幕縮放

  1. 手動調用 editorIns.layout() 方法 文檔
  2. 實例化編輯器的時候 automaticLayout 聲明為 true文檔 (可能有性能問題)

Diff Editor

  1. 通過 monaco.editor.createDiffEditor 方法創建 diff editor 實例;
  2. 通過 diffEditorIns.setModel 方法設置 diff 的原始值和現在的值
diffEditorIns.setModel({
  original: monaco.editor.createModel(originalValue, 'javascript'),
  modified: monaco.editor.createModel(nowValue, 'javascript'),
});

更新編輯器 options

通過 updateOptions 來更新,比如

editorIns.updateOptions({
    readOnly: true,
});

自定義語言高亮

  1. 如果是自定義的語言需要先注冊自定義語言名稱
monaco.languages.register({ id: 'configItem' });
  1. 定義高亮規則 setMonarchTokensProvider 文檔
// 如果是已有語言高亮則不需要第一步直接設置高亮規則就可以
monaco.languages.setMonarchTokensProvider('yaml', {
  tokenizer: {
    root: [[tokenRegx, { token: 'keyword' }]],
  },
});
// 自定義語言
monaco.languages.setMonarchTokensProvider('configItem', {
  tokenizer: {
    root: [[tokenRegx, { token: 'keyword' }]],
  },
});

標記錯誤

通過 monaco.editor.setModelMarkers 方法標記位置點,文檔

monaco.editor.setModelMarkers(
  model,
  'javascript',
  [{
    startLineNumber: 2,
    endLineNumber: 2,
    startColumn: 1,
    endColumn: 10,
    severity: monaco.MarkerSeverity.Error,
    message: `語法錯誤`,
  }],
);

Quick Fix

通過 setModelMarkers 標記錯誤或者警告之后 hover 會有一個 modal 里面展示錯誤信息以及 quick fix 的選項,如何來定義 quick fix 的行為呢。 這里需要通過 monaco.languages.registerCodeActionProvider 來定義quick fix 的行為,支持 edit 和 command 兩種類型的行為。

  1. edit 是直接替換被指定的位置的文本;
  2. command 則是完全的自定義 fix 行為,可以做任何事情。

CompleteProvider

用於定義自動完成的 provider

HoverProvider

用於定義鼠標 hover 的 provider。

public provideHover(
  model: monaco.editor.ITextModel,
  position: monaco.Position,
  token: monaco.CancellationToken,
)

PS: 貌似不支持關鍵詞定義 hover tips 解決方案:

  1. 獲取 hover 位置;
  2. 獲取 hover 的那一行內容 model.getLineContent(lineNumber) ;
  3. 匹配 hover 行關鍵字;
  4. 獲取關鍵字位置;
  5. 根據 鼠標 hover column 確定 hover 的關鍵字 位置;
  6. 提示 關鍵字內容等。

本地化 i18n

目前 monaco-editor 官方僅支持 AMD 方式的 i18n 配置。 補丁方案 monaco-editor-esm-webpack-plugin

Dispose

monaco-editor 中提供了許多的回調以及 provider 供我們使用,一些場景下我們需要 removeEventListener ,這個時候我們可以使用 dispose 來實現。大部分情況下各種回調或 provider 都是返回一個包含 dispose 函數的對象,只要執行下這個函數就可以解除功能。

let disposeable: monaco.IDisposable;

// 取消 hover provider
disposeable?.dispose();

disposeable = monaco.languages.registerHoverProvider(language, new ConfigItemHoverProvider(configItemList));

參考

  1. monaco-editor
  2. monaco-editor playground
  3. monaco-editor-webpack-plugin


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM