前言
- 公司有一个数据中台类的项目,因为之前技术栈比较老迭代不便等种种原因近期开始重构了,这个项目前辈们迭代了三年之久,可想重构起来的工作量[手动狗头],以前端技术栈是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看一下入口文件我们可以看到,
react-monaco-editor封装了MonacoEditor和MonacoDiffEditor帮我们处理了一些括号自动闭合、代码对比... 以及导出了一个monaco的实例便于使用者定制。 -
@monaco-editor/react同样看下入口文件 比上面丰富的一点试@monaco-editor/react帮我们封装了几个声明周期的钩子,考虑再三我决定在项目中使用@monaco-editor/react进行代码编辑器的定制化封装
monaco-editor 版本比较
- 需要注意的是
monaco-editor在0.25.1+代码会有不高亮的问题,解决办法:-
自定义主题(后面会说)
-
使用
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;
```
- 到这里我们可以看到一个拥有基础效果的代码编辑器了
丰富用法
-
当然,大多数应用场景这点是完全不够的,我们需要一些定制化的内容
-
自定义主题
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;看下效果 , 代码颜色以及背景色已经使我们想要的颜色了
-
自定义代码提示
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;
- 看下效果
monaco官方地址 感兴趣的话可以去读一下,有时间的话我会继续补存的.
-END-