• codemirror6教程


    codemirror6教程

    两个概念

    编辑器视图

    视图用于展示文本的,在codemirror6中文本信息的展示使用的是EditorView这个类

    编辑器状态

    在codemirror6中,文本信息放到了EditorState这个类,EditorState可以展示在EditorView之上,改变EditorView里面的文本,可以更改页面上的文本展示。

    安装Codemirror6

    npm install codemirror
    
    • 1

    EditorState

    编辑器状态,描述当前编辑器使用的插件,文本等信息

    创建
    import {EditorState,type Extension} from "@codemirror/state"
    //创建编辑器状态
    let state = EditorState.create({
        doc: str,  //这是文本
        extensions:this.codemirrorPlugin  //传入的插件数组
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    EditorView

    编辑器视图,编辑器的展现

    创建
    let view = new EditorView({
    	state:state, //编辑器状态,编辑器视图创建时初始化的状态
    	parent:element //挂载的dom,可以通过parent挂载到指定的div块
    })
    
    • 1
    • 2
    • 3
    • 4

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    给编辑器动态的注入插件
    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()) 
    }) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    巧妙的封装

    通过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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    插件

    基础插件(basicSetup)

    basicSetup提供了基础的插件功能,如:行数,折叠,历史记录,选择高亮,快捷键映射

    import {basicSetup} from "codemirror"
    EditorState.create({
        doc: str,  //这是文本
        extensions:[basicSetup]  //传入的插件数组
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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
        ])
    ])();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    代码高亮插件
    静态高亮

    如果只是高亮个别代表代码,可以通过加载不同的高亮包去高亮代码

    import { javascript } from '@codemirror/lang-javascript'
    
    EditorState.create({
        doc: str,  //这是文本
        extensions:[javascript()]  //传入的插件数组
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    动态高亮

    如果需要动态加载高亮,需要引用包加载,其中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.support
    
    if(support){//已经加载
        //跟新语言高亮插件支持
    	//...........
    }else{//去加载并跟新
        languageDescription.load().then(s=>{
            //s是语言高亮插件
            //...........
        })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    加载完语言包,还有一个重要的步骤,替换编辑器视图中的语言包,结合上面的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)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在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>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
  • 相关阅读:
    保姆级k8s集群安装教程
    2023年数维杯国际大学生数学建模挑战赛A题
    关于阿里云中RDS数据库的CPU使用率和内存使用率的20道面试题
    Java9-17新特性解读,了解少于3个你可能脱节了
    C++面试八股文:什么是RAII?
    利用 Redis 也能实现订单30分钟自动取消?
    01 关系模型及其相关内容
    CPP-Templates-2nd--第 21 章 模板和继承
    解决局域网内因为不在同一网段无法ping通的问题
    生物素标记链霉亲和素,Biotin-Streptavidin,链霉亲和素-生物素偶联物(SA-Biotin)
  • 原文地址:https://blog.csdn.net/qq_43203949/article/details/128107891