CodeMirror 已升级了 6 版本,变化较大。新版对 ts 、ES6 模块引入等的支持都很好,各个语言、插件等都单独拆成了包,可按需引入,也有一个好用的 react 包装组件。
查看文档
- 官网:https://codemirror.net/
- 文档中的示例,如:https://codemirror.net/examples/autocompletion/
- 查看文档示例代码,要到 github 源码中查看,如以上示例的对应地址为:https://github.com/codemirror/website/blob/master/site/examples/autocompletion/autocompletion.ts
基础使用
安装:
npm i -S codemirror @codemirror/lang-javascript
使用:
import {basicSetup, EditorView} from "codemirror"
import {javascript} from "@codemirror/lang-javascript"
new EditorView({
doc: "console.log('hello')\n",
extensions: [basicSetup, javascript()],
parent: document.body
})
react 包装组件
可使用 react 包装组件 https://uiw.gitee.io/react-codemirror/
npm i -S @uiw/react-codemirror
安装后,即可直接引入编辑器:
import CodeMirror from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';
const editorRef = useRef(null)
<CodeMirror
ref={editorRef}
value="console.log('hello world!');"
height="200px"
extensions={[javascript()]}
onChange={onChange}
/>
extensions 概念
可以看到,使用原生写法和 react 包装都有 extensions 这个传参。这个有点像把 5.x 版本的 mode (语言)和 addons (插件)合并到一起了,调用一个包就能完成语言支持、代码高亮、代码提示等。
组件已将各个语言设置成为了 extensions ,直接调用就可以了。我们也可以拓展一些自己的 extensions,如以下的实践示例。
获取与设置值
通过 ref 可拿到编辑器的 view 对象,进行编辑器值的获取和修改操作。
文档:CodeMirror Document Change Example
值获取与整体替换:
const getValue = () => {
return editorRef.current?.view?.state.doc.toString() || ''
}
const setValue = (val: string) => {
const cm = editorRef.current?.view
cm && cm.dispatch({ changes: { from: 0, to: cm.state.doc.length, insert: val } })
}
将选中的文本替换为指定文本,如未选中时在光标处插入:
const replaceSelection = (val: string) => {
const view = editorRef.current?.view
view && view.dispatch(view.state.replaceSelection(val))
}
语言切换
语言切换改变传入的 extensions 即可。
const langConfigMap = {
js: [javascript()],
java: [java()],
cpp: [cpp()],
}
const langKeys = Object.keys(langConfigMap)
切换:
<Select
value={lang}
onChange={val => setLang(val)}
options={langKeys.map(lang => ({ value: lang, label: lang }))}
/>
传入:
<CodeMirror
extensions={langConfigMap[lang]}
/>
值得一提的是,CodeMirror 对 JS 以外的语言支持较差,一般只能进行代码高亮识别,不支持代码提示等功能,这个在 5.x 版本中也是一样的。
自动换行
引入 codemirror 原生的 EditorView
import { EditorView } from '@codemirror/view'
在 extensions 中增加:
extensions={[...langConfigMap[lang], EditorView.lineWrapping]}
自定义代码提示
代码提示是通过 autocomplete 插件实现的。
文档中,有个示例如下:
import { CompletionContext } from '@codemirror/autocomplete'
function myCompletions(context: CompletionContext) {
let word = context.matchBefore(/\w*/)
if (word.from == word.to && !context.explicit)
return null
return {
from: word.from,
options: [
{label: "match", type: "keyword"},
{label: "hello", type: "variable", info: "(World)"},
{label: "magic", type: "text", apply: "⠁⭒*.✩.*⭒⠁", detail: "macro"}
]
}
}
以上 type 为 text 的示例即为自定义代码提示的用法,基于这个来修改即可。
使以上的代码提示作用于 js 语言:
import { javascriptLanguage } from '@codemirror/lang-javascript'
const jsSnippets = javascriptLanguage.data.of({
autocomplete: myCompletions,
})
在 js 基础语法提示同时支持自定义的提示:
<CodeMirror
extensions={[javascript(), jsSnippets]}
// ... 其他设置
/>
使光标自动定位到 指定位置:
import { snippetCompletion } from '@codemirror/autocomplete'
snippetCompletion('console.log(${})', {
label: 'log',
}),
对比同类库
比起 VSCode 开源的 monaco-editor 编辑器库,CodeMirror 体积更小,性能和兼容性更好,移动端支持更好。