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
來幫助我們處理這些問題,它可以用來做:
- 自動注入getWorkerUrl全局變量;
- 處理worker的編譯配置;
- 自動引入控件和語言包。
相關功能
編輯器適配屏幕縮放
Diff Editor
- 通過
monaco.editor.createDiffEditor
方法創建 diff editor 實例; - 通過
diffEditorIns.setModel
方法設置 diff 的原始值和現在的值
diffEditorIns.setModel({
original: monaco.editor.createModel(originalValue, 'javascript'),
modified: monaco.editor.createModel(nowValue, 'javascript'),
});
更新編輯器 options
通過 updateOptions
來更新,比如
editorIns.updateOptions({
readOnly: true,
});
自定義語言高亮
- 如果是自定義的語言需要先注冊自定義語言名稱
monaco.languages.register({ id: 'configItem' });
- 定義高亮規則 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
兩種類型的行為。
edit
是直接替換被指定的位置的文本;command
則是完全的自定義 fix 行為,可以做任何事情。
CompleteProvider
用於定義自動完成的 provider
HoverProvider
用於定義鼠標 hover 的 provider。
public provideHover(
model: monaco.editor.ITextModel,
position: monaco.Position,
token: monaco.CancellationToken,
)
PS: 貌似不支持關鍵詞定義 hover tips 解決方案:
- 獲取 hover 位置;
- 獲取 hover 的那一行內容
model.getLineContent(lineNumber)
; - 匹配 hover 行關鍵字;
- 獲取關鍵字位置;
- 根據 鼠標 hover column 確定 hover 的關鍵字 位置;
- 提示 關鍵字內容等。
本地化 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));