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));