在Vue中使用CodeMirror实现编写JSON编辑器

最近写了个 JSON 编辑器给自己用,用 CodeMirror 来实现代码编辑器的功能,这边来记录下。

安装依赖

1
2
npm install --save codemirror
npm install --save jsonlint-mod

or

1
2
yarn add codemirror
yarn add jsonlint-mod

代码

这边用的环境时 Vue 3 + Vite 2

要点:

  • 不要将准备被渲染的 textarea 标签放在 template 顶层,在 vue 组件 unbind 时,由 CodeMirror 添加的 DOM 无法自动被移除。
  • 根据需要引入对应的样式和 js
  • JSON 编辑器的 lint 需要引入外部插件jsonlint-mod,不要直接使用jsonlint,不支持通过 import 导入
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<template>
<div class="codePanel"><textarea ref="codemirror"></textarea></div>
</template>

<script>
// 引入CodeMirror和基础样式
import CodeMirror from "codemirror";
import "codemirror/lib/codemirror.css";
// JSON代码高亮需要由JavaScript插件支持
import "codemirror/mode/javascript/javascript.js";
// 选择IDEA主题样式,还有其他很多主题可选
import "codemirror/theme/idea.css";
// 支持使用Sublime快捷键
import "codemirror/keymap/sublime.js";
// 搜索功能的依赖
import "codemirror/addon/dialog/dialog.js";
import "codemirror/addon/dialog/dialog.css";
// 支持搜索功能
import "codemirror/addon/search/search";
import "codemirror/addon/search/searchcursor.js";
// 支持各种代码折叠
import "codemirror/addon/fold/foldgutter.css";
import "codemirror/addon/fold/foldcode.js";
import "codemirror/addon/fold/foldgutter.js";
import "codemirror/addon/fold/brace-fold.js";
import "codemirror/addon/fold/comment-fold.js";
// 支持代码区域全屏功能
import "codemirror/addon/display/fullscreen.css";
import "codemirror/addon/display/fullscreen.js";
// 支持括号自动匹配
import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/addon/edit/closebrackets.js";
// 支持代码自动补全
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/show-hint.js";
import "codemirror/addon/hint/anyword-hint.js";
// 行注释
import "codemirror/addon/comment/comment.js";
// JSON错误检查
import "codemirror/addon/lint/lint.css";
import "codemirror/addon/lint/lint.js";
// 需要依赖全局的jsonlint,不是很优雅
import "codemirror/addon/lint/json-lint.js";
// 引入jsonlint
import jsonlint from "jsonlint-mod";
window.jsonlint = jsonlint;

let codemirror;
export default {
name: "JSON编辑器",
data: () => ({
code: "",
}),
mounted() {
// 防止转为监听对象,vue3中如果CodeMirror对象被转为监听对象,会无法正常使用
codemirror = markRaw(
// 用ref获取需要渲染的textarea的DOM
CodeMirror.fromTextArea(this.$refs.codemirror, {
// JS高亮显示
mode: "application/json",
indentUnit: 2, // 缩进单位,默认2
smartIndent: true, // 是否智能缩进
// 显示行号
styleActiveLine: true,
lineNumbers: true,
// 设置主题
theme: "idea",
// 绑定sublime快捷键
keyMap: "sublime",
// 开启代码折叠
lineWrapping: true,
foldGutter: true,
gutters: [
"CodeMirror-linenumbers",
"CodeMirror-foldgutter",
"CodeMirror-lint-markers",
],
// CodeMirror-lint-markers是实现语法报错功能
lint: true,

// 全屏模式
fullScreen: false,

// 括号匹配
matchBrackets: true,
autoCloseBrackets: true,

// 额外快捷键
extraKeys: {
F11: (cm) => {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
Esc: (cm) => {
if (cm.getOption("fullScreen")) {
cm.setOption("fullScreen", false);
}
},
},
})
);
// 将编辑器中的值存储下来
codemirror.on("change", (cm) => {
this.code = cm.getValue();
});
},
beforeUnmount() {
this.destroy();
},
methods: {
destroy() {
// 获取代表编辑器的DOM
const element = codemirror.doc.cm.getWrapperElement();
// 删除编辑器实例
element && element.remove && element.remove();
},
},
};
</script>