react 集成 codemirror6 知识点全汇总

常见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

里边有许多美观的主题,作用如下:

react 集成 codemirror6 知识点全汇总

运用装备办法都相似,咱们挑选自己喜爱的主题即可。

监听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这个库。

  1. 首要是装置依靠
pnpm i @codemirror/autocomplete --save
  1. 引进代码,及其装备
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]})
  ],
});

完成如下如下:

react 集成 codemirror6 知识点全汇总

留意:以上这种办法,自界说的自动提示会直接掩盖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;

作用如下:

react 集成 codemirror6 知识点全汇总

继续更新中…

后续迭代过程中,有新的一些功用完成点,或者坑都会在这里连续更新和完善。

总结

在整个过程中,主要便是前期对codemirror的版别,以及社区依据react,vue等有许多不同的封装库,有点混乱,不知道该挑选哪一个,这篇文章为咱们全体梳理了一下,同时,把codemirror6的常用功用进行了收拾,期望能够让需求的小伙伴儿能够少走一些坑,快速接入项目中。