常见web代码修改器结构
在接到在线代码修改器的需求之后,就开端了相关的调研,以下目前社区最受欢迎的三个开源计划:
- Ace
- Monaco
- Codemirror
这里就不展开比较三者的优劣,详细这篇文章:「译」Ace,CodeMirror 和 Monaco:Web 代码修改器的对比,已经很详细的对这三大结构做了比较,咱们能够结合实际事务场景,做出自己的技能选型。
最终,咱们团队决议选用 Codemirror
写作不易,假如这篇文章对您有所帮助,欢迎 重视♥️ + 点赞 鼓舞一下作者,感恩~
Codemirror踩坑
在决议选用Codemirror
之后,立即就开端尝试去写一些demo,可是由于前期不了解Codemirror版别较多,且依据react,vue等结构,社区有许多不同的完成库,那到底用哪个版别,用哪个库呢?这中间也踩了不少坑,在这里给咱们梳理一下,让有需求的小伙伴儿们能够少踩一些坑。
首要,说明一下Codemirror的版别,目前主要是用的是两个版别:
- Codemirror6
- 文档:codemirror.net/
- github:github.com/codemirror
- Codemirror5
- 文档:codemirror.net/5/
- github:github.com/codemirror/…
Codemirror6和Codemirror5的主要区别体现在以下几个方面:
- 架构:CM6是对CM5进行了全面重写和重构的版别,选用了新的架构。CM6的设计目标是供给更好的可扩展性、模块化和定制性,以习惯不同的修改器需求。
- 模块化:CM6引进了模块化的概念,使得修改器的功用能够以更灵敏的办法组织和扩展。它供给了一套中心模块,以及可选的插件和扩展模块,使开发人员能够依据自己的需求挑选和组合功用。
- 插件系统:CM6的插件系统更加强大和灵敏。它选用了新的依据状况和触发器的机制,使得插件能够更好地与修改器交互并呼应改变。这使得开发人员能够创立更杂乱和定制化的修改器功用。
- 渲染办法:CM6运用新的渲染引擎,选用了虚拟DOM的概念,以进步功用和呼应才能。它还支撑可选的受限制的线性渲染形式,能够在大型文档上供给更好的功用
因而,2023年的咱们,引荐咱们运用Codemirror6
留意,咱们在网上搜到的大多数关于codemirror的文章依然是v5的版别,想要直接copy代码调试的小伙伴儿们要留意了哦,怎么判别呢?典型的一个判别规范的便是V6的版别选用的ESM模块化的办法去引进,而V5依然是传统的非模块的办法,咱们能够依据这去判别搜到的代码是选用的哪个版别。
确定运用V6
的版别之后,接下来便是要考虑,社区是否有现成的依据React,Vue封装好的Codemirror组件呢?当然是有的:
-
uiwjs/react-codemirror:
- github:github.com/uiwjs/react…
- 完成:依据
codemirror6
以及react16.8+
完成 - 优缺点:优点便是简单易用,直接引进react组件即可,常见的言语设置,主题设置等功用都支撑,可是相对于原生的codemirror来说,功用仍是有限,假如需求对codemirror进行更杂乱的自界说,主张运用原生的codemirror,依据原生的codemirror,自己封装相应的react组件。
-
react-codemirror2
- github:github.com/scniro/reac…
- 完成:依据
codemirror5
以及react16
完成 - 优缺点:相对比较老了,最终一次保护也是在3年前了,在现在较新版别的react中可能会有问题,例如:react18+ 中初始化会报错。
因而,假如仅仅简单场景的在线修改器,uiwjs/react-codemirror
这个库基本能够满足条件,可是假如想自界说相对比较杂乱的场景,主张仍是依据原生的codemirror6
去自己封装相应的组件。
确定运用原生的codemirror6
之后,接下来咱们就看看其基本运用啦。
常见场景
基本运用
Codemirror6选用现代的JavaScript模块化和构建东西,并经过一组模块化的包来完成不同的功用。其间,@codemirror/view
和@codemirror/state
是CodeMirror 6(以下简称CM6)库的中心包之一,用于构建可扩展的代码修改器。
-
@codemirror/view
:这个包供给了构建修改器用户界面(UI)的中心功用。它界说了修改器的视图组件、输入处理、渲染逻辑等。@codemirror/view
中的主要类是EditorView
,它代表了一个CM6修改器实例的视图。你能够运用@codemirror/view
来创立、操控和自界说修改器的外观和交互行为。 -
@codemirror/state
:这个包界说了修改器的状况管理和文档模型。它供给了EditorState
类,用于表明修改器的完整状况,包括文本内容、光标方位、选中规模、修改器的装备选项等。经过@codemirror/state
,你能够创立和管理修改器的状况,执行修改操作、查询修改器状况,以及呼应状况的改变。
以下便是一个依据react最小版别的codemirror在线修改器的完成:
// myCodemirror.tsx
import React, { useRef, useEffect } from 'react';
import { basicSetup } from 'codemirror';
import { EditorView, keymap } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
const CodeMirror: React.FC = () => {
const editorRef = useRef(null);
useEffect(() => {
// 初始化CodeMirror修改器
const state = EditorState.create({
doc: 'hello world!',
extensions: [
basicSetup,
],
});
const editor = new EditorView({
state,
parent: editorRef.current,
});
return () => {
editor.destroy(); // 留意:尔后此处要随组件毁掉
};
}, []);
return <div ref={editorRef}></div>;
};
export default CodeMirror;
言语设置
最小版别的codemirror代码修改器完成今后,接下来,咱们一般都需求进一步指定对应的言语,经过 codemirror6 官方github能够看到,其不同言语都有一个对应的包来保护,咱们在项目中,只需求引进相应的包,并且在extensions
装备即可。
例如:咱们要引进sql言语,首要装置依靠包:
pnpm install @codemirror/lang-sql --save
然后,在依据咱们刚刚的最小修改器代码的根底上,引进该依靠包,就以下两步:
import { sql } from '@codemirror/lang-sql'; // 引进言语包
const state = EditorState.create({
doc: 'hello world!',
extensions: [
basicSetup,
sql(), // 在extensions中装备言语
],
});
完整代码如下:
// myCodemirror.tsx
import React, { useRef, useEffect } from 'react';
import { basicSetup } from 'codemirror';
import { EditorView, keymap } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { sql } from '@codemirror/lang-sql'; // 引进言语包
const CodeMirror: React.FC = () => {
const editorRef = useRef(null);
useEffect(() => {
const state = EditorState.create({
doc: 'hello world!',
extensions: [
basicSetup,
sql(), // 在extensions中装备言语
],
});
const editor = new EditorView({
state,
parent: editorRef.current,
});
return () => {
editor.destroy();
};
}, []);
return <div ref={editorRef}></div>;
};
export default CodeMirror;
主题设置
言语设置完今后,接下来便是设置一个自己喜爱的主题啦,默认情况下,codemirror6 只包含一个主题:@codemirror/theme-one-dark, 如需求运用,直接在项目中装置引进即可
// 装置主题
pnpm install @codemirror/theme-one-dark
// import引进,然后在extensions属性中装备即可。
import { oneDark } from '@codemirror/theme-one-dark'
const state = EditorState.create({
doc: 'hello world!',
extensions: [
//...
oneDark
],
});
当然,假如还想引用其他主题,也能够参考如下两个网站:
- thememirror
- @ddietr/codemirror-themes
里边有许多美观的主题,作用如下:
运用装备办法都相似,咱们挑选自己喜爱的主题即可。
监听doc改变
怎么监听代码改变呢?在extensions
中装备 EditorView.updateListener
即可。代码如下:
const state = EditorState.create({
doc: 'select * from table',
extensions: [
// ...
EditorView.updateListener.of((v) => {
console.log(v.state.doc.toString()) //监测得到的最新代码
}),
],
});
自界说autocomplete
在实际运用中,经常需求自界说一些关键词,例如:公司内部常用的表,字段等信息,咱们需求装备到autocompletion中,这样咱们输入的时分,就能够快速提示,方便输入。
在codemirror中也供给了相应的功用,中心是依靠@codemirror/autocomplete
这个库。
- 首要是装置依靠
pnpm i @codemirror/autocomplete --save
- 引进代码,及其装备
import { autocompletion } 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"}
]
}
}
/// 在extensions中,引进myCompletions
const state = EditorState.create({
doc,
extensions: [
// ...
autocompletion({ override: [myCompletions]})
],
});
完成如下如下:
留意:以上这种办法,自界说的自动提示会直接掩盖sql言语自带的自动提示,显然咱们仅仅想拓展,并不是直接掩盖,这部分怎么完成还再进一步调研中,了解的小伙伴儿欢迎共享。
完整代码
以下是用react封装的一个codemirror组件,包含了根底功用
,言语设置
,主题设置
,doc改变监听
等功用。有需求的小伙伴儿能够直接复制到一个.tsx文件中,在本地查看作用。
import React, { useRef, useEffect, useState } from 'react';
import { basicSetup } from 'codemirror';
import { EditorView, keymap } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import { sql } from '@codemirror/lang-sql';
import { ayuLight } from 'thememirror';
const sqlLang = sql();
const CodeMirror: React.FC = () => {
const editorRef = useRef(null);
const [doc, setDock] = useState();
useEffect(() => {
// 初始化CodeMirror修改器
const state = EditorState.create({
doc,
extensions: [
basicSetup,
sqlLang,
ayuLight,
EditorView.updateListener.of((v) => {
if (v.docChanged) {
setDock(v.state.doc.toString());
}
}),
],
});
const editor = new EditorView({
state,
parent: editorRef.current,
});
return () => {
editor.destroy(); // 留意:尔后此处要随组件毁掉
};
}, []);
return <div ref={editorRef}></div>;
};
export default CodeMirror;
作用如下:
继续更新中…
后续迭代过程中,有新的一些功用完成点,或者坑都会在这里连续更新和完善。
总结
在整个过程中,主要便是前期对codemirror的版别,以及社区依据react,vue等有许多不同的封装库,有点混乱,不知道该挑选哪一个,这篇文章为咱们全体梳理了一下,同时,把codemirror6的常用功用进行了收拾,期望能够让需求的小伙伴儿能够少走一些坑,快速接入项目中。