codemirror6教程
文章目录
- codemirror6教程
- 两个概念
- 编辑器视图
- 编辑器状态
- 安装Codemirror6
- EditorState
- 创建
- EditorView
- 创建
- Compartment
- 创建
- 给编辑器动态的注入插件
- 巧妙的封装
- 插件
- 基础插件(basicSetup)
- 代码高亮插件
- 静态高亮
- 动态高亮
- 在vue中的使用
两个概念
编辑器视图
视图用于展示文本的,在codemirror6
中文本信息的展示使用的是EditorView
这个类
编辑器状态
在codemirror6中,文本信息放到了EditorState
这个类,EditorState
可以展示在EditorView
之上,改变EditorView
里面的文本,可以更改页面上的文本展示。
安装Codemirror6
npm install codemirror
EditorState
编辑器状态,描述当前编辑器使用的插件,文本等信息
创建
import {EditorState,type Extension} from "@codemirror/state"
//创建编辑器状态
let state = EditorState.create({doc: str, //这是文本extensions:this.codemirrorPlugin //传入的插件数组
})
EditorView
编辑器视图,编辑器的展现
创建
let view = new EditorView({state:state, //编辑器状态,编辑器视图创建时初始化的状态parent:element //挂载的dom,可以通过parent挂载到指定的div块
})
Compartment
- 一个特殊的插件类,也叫隔层,用于封装真正的插件,当插件传入EditorState后,我们是无法直接动态改变里面的插件的,如果要改变里面的插件,就需要用到Compartment封装插件。
- Compartment就像一个隔箱一样,里面装插件
- Compartment使用场景:用户需要根据选择的语言,动态更改语法高亮。(通过Compartment去修改编辑器的高亮插件)
创建
import {Compartment} from "@codemirror/state"
import { javascript } from '@codemirror/lang-javascript'
import {EditorState,Extension} from "@codemirror/state"const compartment = new Compartment()let state = EditorState.create({doc: "hello!!!", //这是文本extensions:[compartment.of(javascript()) //] //传入的插件数组
})//判断当前编辑器中是否存在当前的compartment封装过的插件
//当flag为真时,当前编辑器存在当前的compartment封装过的插件
let flag = compartment.get(view.state)
给编辑器动态的注入插件
import {EditorState,Extension, Compartment,StateEffect} from "@codemirror/state"
import {EditorView} from "@codemirror/view"
import {basicSetup} from "codemirror"
import { javascript } from '@codemirror/lang-javascript'
import {java} from '@codemirror/lang-java'let state = EditorState.create({doc: "hello!!!", //这是文本extensions:[basicSetup] //传入的插件数组
})
let view = new EditorView({state:state, //编辑器状态,编辑器视图创建时初始化的状态parent:element //挂载的dom,可以通过parent挂载到指定的div块
})
let compartment = new Compartment()// inject,向编辑器注入插件(如果在EditorState创建时传入,可以忽略这一步)
view.dispatch({ //通过dispatch发送事务effects: StateEffect.appendConfig.of(compartment.of(javascript()))
})// reconfigure,向编辑器修改某个插件
view.dispatch({ effects: compartment.reconfigure(java())
})
巧妙的封装
通过createEditorCompartment()
函数,我们就可以巧妙地封装插件
import {EditorState,type Extension, Compartment,StateEffect} from "@codemirror/state"
import {EditorView} from "@codemirror/view"
import { javascript } from '@codemirror/lang-javascript'
import {java} from '@codemirror/lang-java'
/*** 创建一个compartment,并和对其修改的run函数* @param view * @returns */// https://codemirror.net/examples/config/// https://github.com/uiwjs/react-codemirror/blob/22cc81971a/src/useCodeMirror.ts#L144// https://gist.github.com/s-cork/e7104bace090702f6acbc3004228f2cb
const createEditorCompartment = () => {const compartment = new Compartment()const run = (extension: Extension,view: EditorView) => {if(compartment.get(view.state)){//动态地重新配置插件view.dispatch({ effects: compartment.reconfigure(extension) }) // reconfigure}else{//向编辑器注入某一个插件view.dispatch({ effects: StateEffect.appendConfig.of(compartment.of(extension)) })// inject}}return { compartment, run }
}//使用
let {compartment, run} = createEditorCompartment()
//注入
run(javascript(),view)
//修改
run(java(),view)
插件
基础插件(basicSetup)
basicSetup提供了基础的插件功能,如:行数,折叠,历史记录,选择高亮,快捷键映射
import {basicSetup} from "codemirror"
EditorState.create({doc: str, //这是文本extensions:[basicSetup] //传入的插件数组
})
basicSetup的源码
const basicSetup = (() => [view.lineNumbers(), //行数view.highlightActiveLineGutter(),view.highlightSpecialChars(),commands.history(), //历史插件language.foldGutter(), //折叠view.drawSelection(),view.dropCursor(),state.EditorState.allowMultipleSelections.of(true), //复数选择(编辑器查找替换功能会用到)language.indentOnInput(),language.syntaxHighlighting(language.defaultHighlightStyle, { fallback: true }),language.bracketMatching(),autocomplete.closeBrackets(),autocomplete.autocompletion(), //语法提示view.rectangularSelection(),view.crosshairCursor(),view.highlightActiveLine(), //激活行高亮插件search.highlightSelectionMatches(), //选择匹配高亮view.keymap.of([ //一些快捷键映射...autocomplete.closeBracketsKeymap,...commands.defaultKeymap,...search.searchKeymap,...commands.historyKeymap,...language.foldKeymap,...autocomplete.completionKeymap,...lint.lintKeymap])
])();
代码高亮插件
静态高亮
如果只是高亮个别代表代码,可以通过加载不同的高亮包去高亮代码
import { javascript } from '@codemirror/lang-javascript'EditorState.create({doc: str, //这是文本extensions:[javascript()] //传入的插件数组
})
动态高亮
如果需要动态加载高亮,需要引用包加载,其中languageDescription.support
指向的是高亮插件,只有当语言包加载了后languageDescription.support
才不为空
//语言包描述
import {LanguageDescription} from "@codemirror/language"
//语言包
import {languages} from "@codemirror/language-data"//根据语言名称匹配语言描述信息
const languageDescription = LanguageDescription.matchLanguageName(languages, "java", true);
//语言高亮插件支持
let support = languageDescription.supportif(support){//已经加载//跟新语言高亮插件支持//...........
}else{//去加载并跟新languageDescription.load().then(s=>{//s是语言高亮插件//...........})
}
加载完语言包,还有一个重要的步骤,替换编辑器视图中的语言包,结合上面的Compartment,我们就可以很轻松的对高亮插件进行注入和修改。
//语言包描述
import {LanguageDescription} from "@codemirror/language"
//语言包
import {languages} from "@codemirror/language-data"/*** 创建一个compartment,并和对其修改的run函数* @param view * @returns */// https://codemirror.net/examples/config/// https://github.com/uiwjs/react-codemirror/blob/22cc81971a/src/useCodeMirror.ts#L144// https://gist.github.com/s-cork/e7104bace090702f6acbc3004228f2cb
const createEditorCompartment = () => {const compartment = new Compartment()const run = (extension: Extension,view: EditorView) => {if(compartment.get(view.state)){//动态地重新配置插件view.dispatch({ effects: compartment.reconfigure(extension) }) // reconfigure}else{//向编辑器注入某一个插件view.dispatch({ effects: StateEffect.appendConfig.of(compartment.of(extension)) })// inject}}return { compartment, run }
}let state = EditorState.create({doc: "hello!!!", //这是文本extensions:[basicSetup] //传入的插件数组
})
let view = new EditorView({state:state, //编辑器状态,编辑器视图创建时初始化的状态parent:element //挂载的dom,可以通过parent挂载到指定的div块
})
//根据语言名称匹配语言描述信息
const languageDescription = LanguageDescription.matchLanguageName(languages, "java", true);
//注入Java高亮插件
languageDescription.load().then(support=>{run(support,view)
})
在vue中的使用
<template><div id="editor"></div>
</template><script lang="ts" setup>
import {onMounted} from 'vue'
import {EditorState,Extension, Compartment,StateEffect} from "@codemirror/state"
import {EditorView} from "@codemirror/view"
import {basicSetup} from "codemirror"/*** 创建一个compartment,并和对其修改的run函数* @param view * @returns */// https://codemirror.net/examples/config/// https://github.com/uiwjs/react-codemirror/blob/22cc81971a/src/useCodeMirror.ts#L144// https://gist.github.com/s-cork/e7104bace090702f6acbc3004228f2cb
const createEditorCompartment = () => {const compartment = new Compartment()const run = (extension: Extension,view: EditorView) => {if(compartment.get(view.state)){//动态地重新配置插件view.dispatch({ effects: compartment.reconfigure(extension) }) // reconfigure}else{//向编辑器注入某一个插件view.dispatch({ effects: StateEffect.appendConfig.of(compartment.of(extension)) })// inject}}return { compartment, run }
}//动态语言包函数
let {compartment, run } = createEditorCompartment()
let editor = null
const updateLang = (lang:string) => {//根据语言名称匹配语言描述信息const languageDescription = LanguageDescription.matchLanguageName(languages, "java", true);//注入高亮插件languageDescription.load().then(support=>{run(support,editor)})
}//挂载
onMounted(() => {let element = document.getElementById("editor")let state = EditorState.create({doc: "hello!!!", //这是文本extensions:[basicSetup] //传入的插件数组})let view = new EditorView({state:state, //编辑器状态,编辑器视图创建时初始化的状态parent:element //挂载的dom,可以通过parent挂载到指定的div块})editor = view
})</script>