CodeMirror 概述


CodeMirror 概述

参考

CodeMirror 用于在 Web 平台构建代码编辑器,它支持扩展以实现丰富的功能(例如语法高亮、代码块折叠等)

注意

该系列文章主要介绍 CodeMirror 6

其他版本的 CodeMirror 可以参考相关官方文档

模块化

CodeMirror 采用模块化设计,需要导入多个库(推荐使用 bundler 进行打包)才能够构建一个完整的代码编辑器,其中核心库有 3 个:

  • @codemirror/state 模块:定义数据结构,以表示代码编辑器的内容,以及描述修改内容的操作
  • @codemirror/view 模块:将代码编辑器展示到页面上,并响应用户的操作以更新内容
  • @codemirror/commands 模块:用于创建指令(一般与按键绑定),以编程的方式更改内容

不可变数据

指导 CodeMirror 架构的一个宗旨是采用函数式(纯)代码比命令式代码更易于处理,因为函数式代码创建新值而不是产生副作用。

编辑器状态 state(包含编辑器内容、选区等信息)是不可变的 immutable。CodeMirror 响应用户对编辑器的操作时,会生成新的状态值,而旧的状态值是保持不变的。

提示

同时拥有旧状态和新状态通常非常有用,方便进行历史版本的管理。

ts
let state = EditorState.create({doc: "123"})
// ⚠️ 以下操作不可行,不能直接对原有状态赋值(因为这会修改旧状态)
state.doc = Text.of("abc") // <- DON'T DO THIS

需要通过分发事务 dispatch transaction 的方式来更新编辑器状态(而不能直接更改原有的状态值),这会同步通知视图进行更新以呈现新的状态

ts
// 创建事务
// (Assume view is an EditorView instance holding the document "123".)
let transaction = view.state.update({changes: {from: 0, insert: "0"}})
console.log(transaction.state.doc.toString()) // "0123"
// At this point the view still shows the old state.

// 分发事务
view.dispatch(transaction)
// And now it shows the new state.

在 CodeMirror 中的数据流动方向:视图 view 监听用户操作所触发的 DOM 事件(或编辑器 dispatch 的指令) ➡️ 通过事务 transaction 对编辑器状态进行修改(生成新的编辑器状态 state) ➡️ 视图基于新的编辑器状态更新页面

单向数据流
单向数据流

位置系统

CodeMirror 使用数字来表示文档的每个位置

提示

除去装饰器、标记等额外的样式,CodeMirror 代码编辑器的文档内容实际上只包含纯文本,如果每一个字符表示一个单位,则使用数字就可以很方便地表示整个文档的各个位置

一般字符数量和文档位置的定位索引值都是一一对应

实际而言是 UTF-16 编码的字符计作 1unit,而 astral characters 超出 Unicode 标准 BMP 范围的字符(范围为 U+0000U+FFFF)计作 2 个 unit,例如 🤩 表情符号(其 Unicode 编码为 U+1F929

另外换行符也计作 1 个 unit(即使换行符包含多个字符,例如默认换行符包括 "\n"(换行符)、"\r"(回车符)、"\r\n"(回车符+换行符),CodeMirror 也支持设置自定义的换行符,在文档位置定位系统中它们都会被解析为 1 个 unit)

文档的每个位置都可以用数字表示,那么选区 selection 框选的范围文档更改所发生 changes 的位置装饰器 decorate 应用的位置等场景都可以用数字来描述

插件系统

CodeMirror 通过插件为编辑器添加丰富的功能,例如在编辑器的侧栏显示行号,撤销与重做功能等


Copyright © 2025 Ben

Theme BlogiNote

Icons from Icônes