CodeMirror 是一个用 JavaScript 编写的功能强大的文本编辑器库,专为网页端设计,尤其适用于代码编辑场景。它提供了丰富的功能,适用于开发者、教育平台、在线 IDE 或需要代码编辑支持的 Web 应用。以下是其主要功能:
一、CodeMirror简介
1. 核心功能
- 语法高亮
支持 100+ 编程语言(通过模式插件实现),包括 JavaScript、Python、HTML/CSS、C++ 等,高亮规则可自定义。 - 行号显示
自动显示行号,支持自定义格式或动态隐藏。 - 代码折叠
根据语法结构(如函数、循环块)折叠代码区域,提升长代码的可读性。 - 智能缩进
根据语言特性自动缩进,支持手动调整缩进规则。
2. 交互与编辑
- 多光标编辑
支持同时操作多个光标,批量修改代码(类似 Sublime Text/VSCode)。 - 键盘快捷键
内置常用快捷键(复制、注释等),支持自定义绑定,可集成 Vim/Emacs 键位模式(通过插件)。 - 括号匹配与自动闭合
自动高亮匹配的括号,输入时自动补全括号、引号等符号。 - 撤销/重做历史
完整的编辑历史记录,可配置历史深度。
3. 扩展性与集成
-
插件系统
通过插件扩展功能,例如:
- Linter 集成:实时代码检查(需结合 ESLint 等工具)。
- 自动补全 :上下文感知的代码提示(通过
@codemirror/autocomplete
)。 - Git Diff 显示 :高亮代码变更(如
@codemirror/history
)。
-
主题定制
提供多种内置主题(如 Dracula、Solarized),支持 CSS 自定义样式。
-
事件处理 API
监听内容变化、光标移动、焦点事件等,便于与其他组件交互。
4. 高级功能
- 协同编辑
通过附加库(如@codemirror/collab
)实现多人实时协作编辑。 - 移动端支持
优化触屏操作,支持手势和虚拟键盘交互。 - 可访问性(a11y)
支持屏幕阅读器和键盘导航,符合 ARIA 标准(CodeMirror 6 重点改进)。 - 性能优化
虚拟滚动技术处理大文件,响应式设计保障流畅体验。
5. 框架兼容性
- 可与主流前端框架(React、Vue.js、Angular)集成,提供官方或社区维护的封装库(如
@uiw/react-codemirror
)。 - 模块化设计,支持按需加载功能,减少打包体积。
6. 版本特性
- CodeMirror 6 是当前主要版本,采用现代技术栈(TypeScript 重写),提供更清晰的 API 和更强的扩展性。旧版(CodeMirror 5)仍广泛使用但不再更新。
适用场景
- 在线代码编辑器(如 JSFiddle、CodePen)
- 文档工具中的代码片段嵌入
- 教育平台的编程练习环境
- 浏览器的开发者工具扩展
资源
- 官方文档:codemirror.net
- GitHub 仓库:github.com/codemirror/...(v5)
github.com/codemirror/...(v6)
CodeMirror 的灵活性和丰富的生态使其成为 Web 端代码编辑的首选解决方案之一。
CodeMirror与Monacoeditor对比
CodeMirror 和 Monaco Editor 都是流行的 Web 端代码编辑器库,但它们的设计目标、功能侧重和适用场景有所不同。以下是两者的详细对比:
1. 背景与定位
特性 | CodeMirror | Monaco Editor |
---|---|---|
开发者 | Marijn Haverbeke(独立开发者) | Microsoft(VS Code 团队) |
核心目标 | 轻量级、高度可定制、通用代码编辑场景 | 提供接近 IDE 的编辑体验(VS Code 核心) |
体积 | 约 200--500 KB(按需加载) | 约 20--30 MB(完整功能,需优化加载) |
开源协议 | MIT | MIT |
2. 核心功能对比
语法高亮与语言支持
-
CodeMirror
- 支持 100+ 语言(通过模式插件)。
- 高亮规则基于正则表达式,灵活性高但复杂语言(如 TypeScript)支持较弱。
-
Monaco
- 内置 VS Code 的语言服务(TypeScript/JavaScript、CSS、HTML、JSON 等)。
- 对 TypeScript 的智能感知(类型推断、重构)支持最佳。
代码智能提示(IntelliSense)
-
CodeMirror
- 需通过插件(如
@codemirror/autocomplete
)实现基础提示,功能较简单。 - 需要手动集成语言服务(如 Tern.js)。
- 需通过插件(如
-
Monaco
- 原生深度集成 VS Code 的智能提示、参数提示、快速修复等。
- 支持 TypeScript 类型检查、跳转到定义、引用查找等 IDE 级功能。
性能与渲染
-
CodeMirror
- 虚拟滚动优化,适合大文件(10k+ 行)编辑,内存占用低。
- 默认渲染较简单,依赖 DOM 操作。
-
Monaco
- 基于
canvas
渲染,性能极高,但大文件(如 100k 行)可能卡顿。 - 集成复杂语言服务时资源消耗较高。
- 基于
扩展性
-
CodeMirror
- 模块化设计,通过插件系统灵活扩展,社区插件丰富。
- 可自定义主题、快捷键、交互逻辑。
-
Monaco
- 扩展性依赖 VS Code 的 API 设计,功能更强大但定制成本高。
- 支持加载 VS Code 主题(如
monaco-themes
库)。
3. 集成与使用场景
场景 | CodeMirror 优势 | Monaco 优势 |
---|---|---|
轻量级编辑器 | ✅ 体积小,适合嵌入博客、文档工具 | ❌ 体积过大,需按需加载 |
在线 IDE | ✅ 灵活定制,适合教学/简单编码环境 | ✅ 接近本地 IDE 体验,适合复杂项目 |
移动端兼容性 | ✅ 触屏优化较好 | ❌ 对移动端支持有限(如虚拟键盘问题) |
框架集成 | ✅ 官方支持 React/Vue 封装库 | ✅ 提供 React 封装(如 @monaco-editor/react ) |
协作编辑 | ✅ 通过插件实现(如 @codemirror/collab ) |
❌ 需自行实现或依赖其他库 |
4. 典型用例
-
CodeMirror
- 轻量级场景:CodePen、JSFiddle 的早期版本、Markdown 编辑器(如 Jupyter Notebook)。
- 教育平台:LeetCode 的代码练习框、在线编程课程。
-
Monaco Editor
- 复杂 IDE:VS Code 网页版(vscode.dev)、GitHub Codespaces。
- 企业工具:云开发环境(如 CodeSandbox)、低代码平台的高级模式。
5. 开发体验
维度 | CodeMirror | Monaco Editor |
---|---|---|
文档 | 清晰但分散(需查插件文档) | 官方文档详细,但部分 API 复杂 |
调试 | 基于 DOM,易排查样式问题 | 依赖浏览器开发者工具,调试渲染层较难 |
社区生态 | 插件丰富,但质量参差不齐 | 依赖 VS Code 生态,插件标准化程度高 |
学习曲线 | 较平缓(适合快速集成) | 较陡峭(需理解 VS Code 架构) |
6. 如何选择?
优先选 CodeMirror 的情况
- 需要轻量级、快速加载的编辑器(如移动端优先)。
- 项目对定制化要求极高(如非标准语法高亮)。
- 资源受限(服务器带宽或低端设备兼容性)。
优先选 Monaco Editor 的情况
- 需要接近 VS Code 的编辑体验(如智能提示、代码导航)。
- 项目重度依赖 TypeScript/JavaScript 语言服务。
- 已有 VS Code 生态的技术栈(如使用 LSP 协议)。
7. 优化技巧
-
CodeMirror
- 使用 Tree Shaking 仅导入必要模块(CodeMirror 6 支持 ES 模块)。
- 延迟加载语言模式插件。
-
Monaco Editor
- 通过
monaco-editor-webpack-plugin
按需打包语言和功能。 - 使用 CDN 加载核心文件(如
unpkg.com
)。
- 通过
总结
- CodeMirror 是「瑞士军刀」:轻便灵活,适合通用代码编辑场景。
- Monaco Editor 是「重型武器」:功能强大,适合需要 IDE 级体验的复杂应用。
根据项目需求权衡体积、功能和开发成本,两者均可通过配置达到较优平衡。
CodeMirror的sql语法高亮、错误提示、自动补全
在 CodeMirror 中实现 SQL 的 语法高亮 、错误提示 和 自动补全,需要结合语言包、Linter 插件和自定义自动补全逻辑。以下是完整实现步骤和示例代码:
1. 安装依赖
bash
npm install @codemirror/lang-sql @codemirror/lint @codemirror/autocomplete
2. 基础配置(语法高亮 + 行号)
javascript
import { EditorView, basicSetup } from "codemirror";
import { sql } from "@codemirror/lang-sql";
// 创建编辑器实例(默认 SQL 语法高亮)
const editor = new EditorView({
extensions: [
basicSetup, // 包含行号、基础快捷键等
sql({
dialect: 'mysql', // 可选方言: 'postgresql', 'sqlite', 'mssql'
upperCaseKeywords: true, // 自动大写关键字(如 SELECT)
}),
],
parent: document.querySelector("#editor"),
});
3. 错误提示(Linting)
使用 @codemirror/lint
集成 SQL 语法检查工具(例如 sql-lint
或自定义逻辑):
3.1 安装 sql-lint
bash
npm install sql-lint
3.2 配置 Linter
javascript
import { linter, lintGutter } from "@codemirror/lint";
import { SQLint } from "sql-lint";
// 自定义 SQL 语法检查逻辑
const sqlLinter = linter((view) => {
const code = view.state.doc.toString();
const errors = SQLint.lint(code); // 使用 sql-lint 检查
return errors.map((error) => ({
from: error.position.start, // 转换为 CodeMirror 位置
to: error.position.end,
message: error.message,
severity: "error", // 或 'warning'
}));
});
// 在编辑器扩展中添加 lint
const editor = new EditorView({
extensions: [
basicSetup,
sql(),
lintGutter(), // 显示行号旁的错误图标
sqlLinter, // 应用语法检查
],
parent: document.querySelector("#editor"),
});
4. 自动补全(Autocomplete)
通过 @codemirror/autocomplete
实现静态关键字补全和动态元数据补全。
4.1 静态关键字补全
javascript
import { autocompletion, CompletionContext } from "@codemirror/autocomplete";
// SQL 关键字列表
const SQL_KEYWORDS = [
"SELECT", "FROM", "WHERE", "JOIN", "GROUP BY", "ORDER BY",
"INSERT INTO", "UPDATE", "DELETE", "CREATE TABLE", "ALTER TABLE",
];
// 自定义补全逻辑
function sqlKeywordCompletion(context: CompletionContext) {
const word = context.matchBefore(/\w*/);
if (!word) return null;
return {
from: word.from,
options: SQL_KEYWORDS.map((keyword) => ({
label: keyword,
type: "keyword", // 显示关键字图标
})),
};
}
4.2 动态表名/列名补全(需结合后端 API)
javascript
// 假设从 API 获取表名和列名
async function fetchTableNames() {
const res = await fetch("/api/tables");
return await res.json(); // 返回 ['users', 'orders']
}
async function fetchColumns(table: string) {
const res = await fetch(`/api/tables/${table}/columns`);
return await res.json(); // 返回 ['id', 'name', 'email']
}
// 动态上下文补全
function dynamicTableCompletion(context: CompletionContext) {
const line = context.state.doc.lineAt(context.pos);
const textBefore = line.text.slice(0, context.pos - line.from);
// 检测是否在 FROM 子句后输入表名
if (textBefore.match(/FROM\s*$/i)) {
return {
from: context.pos,
options: (await fetchTableNames()).map((table) => ({
label: table,
type: "table",
})),
};
}
// 检测是否在 WHERE 子句后输入列名
if (textBefore.match(/WHERE\s*(\w+.)?/i)) {
const table = "users"; // 需根据上下文推断当前表名(复杂逻辑需自行实现)
return {
from: context.pos,
options: (await fetchColumns(table)).map((col) => ({
label: col,
type: "column",
})),
};
}
return null;
}
4.3 合并补全逻辑
javascript
const editor = new EditorView({
extensions: [
basicSetup,
sql(),
autocompletion({
override: [sqlKeywordCompletion, dynamicTableCompletion],
}),
],
parent: document.querySelector("#editor"),
});
5. 完整集成示例
javascript
import { basicSetup, EditorView } from "codemirror";
import { sql } from "@codemirror/lang-sql";
import { linter, lintGutter } from "@codemirror/lint";
import { autocompletion, CompletionContext } from "@codemirror/autocomplete";
import { SQLint } from "sql-lint";
// 1. 配置 Linter
const sqlLinter = linter((view) => {
// ... 同前文错误检查逻辑
});
// 2. 配置自动补全
const sqlCompleter = (context: CompletionContext) => {
// ... 合并静态关键字和动态补全逻辑
};
// 3. 创建编辑器
const editor = new EditorView({
extensions: [
basicSetup,
sql({ dialect: "mysql" }),
lintGutter(),
sqlLinter,
autocompletion({ override: [sqlCompleter] }),
],
parent: document.querySelector("#editor"),
});
6. 高级优化技巧
-
按需加载方言
javascriptimport { MySQL, PostgreSQL } from "@codemirror/lang-sql"; sql({ dialect: MySQL }); // 明确指定 MySQL 方言
-
主题定制
使用
@codemirror/theme-one-dark
或自定义 CSS:css.cm-editor { height: 400px; border: 1px solid #ddd; } .cm-lint-marker-error { background-image: url("error-icon.svg"); }
-
性能优化
-
对动态补全请求添加防抖(debounce):
javascriptimport { debounce } from "lodash"; const debouncedFetch = debounce(fetchTableNames, 300);
-
缓存元数据(如表结构)减少 API 调用。
-