vue-codemirror代码编辑器使用心得和踩坑
最近工作中需要优化下之前的网页端编辑器,我作为后端开发,虽然做这个不专业,但也只能硬着头皮上啊,大量查阅资料,还是优化了一些内容的,在这里分析一下。
最近工作中需要优化下之前的网页端代码编辑器。我作为后端开发,虽然做这个不专业,但也只能硬着头皮上啊,大量查阅资料,还是优化了一些内容的,在这里分享一下。如果有写的不对的地方,也请大家体谅下,毕竟纯手打很累的哈哈。
参考手册:
vue-codemirror github 地址: https://github.com/surmon-china/vue-codemirror
codemirror 中文文档:https://olindk.gitbooks.io/codemirror/content/configuration.html
codemirror 英文文档:https://codemirror.net/doc/manual.html#config
如何引入 vue-codemirror 就不详细写了,网上资料很多。在 vue-codemirror gitbub 中也有简单教程,此文章只列举一些我认为挺有用的功能。
options配置
codemirror 中最重要的就是配置,这里先贴出来我用的配置。
cmOptions: {
theme: 'monokai',
mode: '',
readOnly: false,
tabSize: 4, // 制表符
indentUnit: 2, // 缩进位数
lineNumbers: true,
ineWiseCopyCut: true,
viewportMargin: 1000,
autofocus: true,
autocorrect: true,
spellcheck: true,
specialChars: /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g,
specialCharPlaceholder: function (ch) {
let token = document.createElement("span");
let content = "\u002e";
token.className = "cm-invalidchar";
if (typeof content == "string") {
token.appendChild(document.createTextNode(content));
}
token.title = "\\u" + ch.charCodeAt(0).toString(16);
token.setAttribute("aria-label", token.title);
return token
},
extraKeys: {
Tab: (cm) => {
if (cm.somethingSelected()) { // 存在文本选择
cm.indentSelection('add'); // 正向缩进文本
} else { // 无文本选择
cm.replaceSelection(Array(cm.getOption("indentUnit") + 1).join(" "), "end", "+input"); // 光标处插入 indentUnit 个空格
}
},
},
lint: false,
// 代码折叠
gutters: [
"CodeMirror-lint-markers",
"CodeMirror-linenumbers",
"CodeMirror-foldgutter"
],
lineWrapping: false,
foldGutter: true, // 启用行槽中的代码折叠
autoCloseBrackets: true, // 自动闭合符号
autoCloseTags: true,
matchTags: { bothTags: true },
matchBrackets: true, // 在光标点击紧挨{、]括号左、右侧时,自动突出显示匹配的括号 }、]
styleSelectedText: true,
styleActiveLine: true,
autoRefresh: true,
highlightSelectionMatches: {
minChars: 2,
trim: true,
style: "matchhighlight",
showToken: false
},
hintOptions: {
completeSingle: false
}
}
1)代码自动提示和补全
代码提示和补全功能,需要引入 codemirror/addon/hint 目录中的如下文件
import 'codemirror/addon/hint/show-hint.css'
import 'codemirror/addon/hint/show-hint.js'
import 'codemirror/addon/hint/javascript-hint'
import 'codemirror/addon/hint/xml-hint'
import 'codemirror/addon/hint/sql-hint'
import 'codemirror/addon/hint/anyword-hint'
代码提示需要一个事件,我这里用的是 inputRead 事件(也可以用别的事件,效果会略微不同),当监听到输入时,判断是否需要提示,所以要在编辑器初始化完成时,启动这个监听,这里只监听了英文字母的输入。编辑器初始化好后会触发 @ready 事件,在 onCmReady 方法中监听 inputRead 事件。然后只要有英文字母输入,就会监听到,自动调用 cm 的 showHint 方法进行提示。
<codemirror
ref="myCm"
v-model="content"
:options="cmOptions"
@ready="onCmReady"
@blur="onCmBlur"
@mousedown.native="onMouseDown">
</codemirror>
onCmReady(cm) {
// 这里的 cm 对象就是 codemirror 对象,等于 this.$refs.myCm.codemirror
cm.on("inputRead", (cm, obj) => {
if (obj.text && obj.text.length > 0) {
let c = obj.text[0].charAt(obj.text[0].length - 1)
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
cm.showHint({ completeSingle:false })
}
}
})
}
提示框的层级问题
基本上增加了如上内容后,在编写代码时就有提示功能了,但是我遇到个问题就是提示框不出来,但是在源码中加日志后发现提示文本是有打印且正确的,后来发现是层级问题。
找到提示框的样式如下,默认的 z-index 是10,太小了,我改到超过2000后才能显示出来。
.CodeMirror-hints {
position: absolute;
z-index: 10;
overflow: hidden;
list-style: none;
margin: 0;
padding: 2px;
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
border-radius: 3px;
border: 1px solid silver;
background: white;
font-size: 90%;
font-family: monospace;
max-height: 20em;
overflow-y: auto;
}
最终的效果:
2)代码折叠
代码折叠同样是个非常重要的功能,需要引入如下文件。
最后那个 indent-fold 不要漏了,我就是因为漏了这文件,发现 python 代码无法折叠,debug了很久源码才找到原因,浪费了很多时间!当然,如果用不到的话可以不引入。
import 'codemirror/addon/fold/foldgutter.css'
import 'codemirror/addon/fold/foldcode'
import 'codemirror/addon/fold/foldgutter'
import 'codemirror/addon/fold/brace-fold'
import 'codemirror/addon/fold/comment-fold'
import 'codemirror/addon/fold/markdown-fold'
import 'codemirror/addon/fold/xml-fold'
import 'codemirror/addon/fold/indent-fold'
几个重要的参数如下:
// 代码折叠
gutters: [
"CodeMirror-lint-markers",
"CodeMirror-linenumbers",
"CodeMirror-foldgutter"
],
foldGutter: true, // 启用行槽中的代码折叠
做完这些配置后,代码就应该可以折叠了,无需额外写 js。
3)以小红点方式显示空格
两个重要的配置:
specialChars :正则表达式,用于描述哪些特殊字符应该被替换为special placeholder。通常用于无法打印的特殊字符。默认为/[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/。
specialCharPlaceholder :当传入一个与specialChars
匹配的字符时,返回一个用于替换的DOM节点。默认为一个红色的点(·)
这个功能也挺有意思的,其实开启的话很简单,只要增加 specialChars 参数,正则中加上空格就行了,但是呢,默认的样式很丑,是个很大很深的红点,如下图所示:
所以呢必须要改,那么查看 codemirror.js 源码,下面贴出关键的部分:
function defaultSpecialCharPlaceholder(ch) {
var token = elt("span", "\u2022", "cm-invalidchar");
token.title = "\\u" + ch.charCodeAt(0).toString(16);
token.setAttribute("aria-label", token.title);
return token
}
function elt(tag, content, className, style) {
var e = document.createElement(tag);
if (className) { e.className = className; }
if (style) { e.style.cssText = style; }
if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
return e
}
根据源码中的 defaultSpecialCharPlaceholder 和 elt 两个方法,我自定义了specialCharPlaceholder 的配置,用于替代默认的空格样式。这里去掉了一些我用不到的,比如非字符串的校验等。然后将大的点替换成了小的点,编码为 \u002e ,自定义的配置如下:
specialChars: /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g,
specialCharPlaceholder: function (ch) {
let token = document.createElement("span");
let content = "\u002e";
token.className = "cm-invalidchar";
if (typeof content == "string") {
token.appendChild(document.createTextNode(content));
}
token.title = "\\u" + ch.charCodeAt(0).toString(16);
token.setAttribute("aria-label", token.title);
return token
}
这里specialChars我默认没改的,因为我想要的效果是默认不显示红点,当我想显示红点时再开启。所以我增加了一个开关,当设置为true时, 在 specialChars 的正则中增加 \s (\s表示空格),这样空格就能显示为我想要的小红点了。
并且对 cm-invalidchar 的样式也改了下,颜色修改为淡点的红色,颜色代码为:#909399
最终的样式如下:
4)制表符替换为4个空格
options中增加 extraKeys 配置,修改默认的tab行为。至于替换为几个空格数,是由参数 indentUint 控制的。
代码如下,这段是很久以前刚弄这个编辑器时,从某篇文章中借鉴的。
extraKeys: {
Tab: (cm) => {
if (cm.somethingSelected()) { // 存在文本选择
cm.indentSelection('add'); // 正向缩进文本
} else { // 无文本选择
cm.replaceSelection(Array(cm.getOption("indentUnit") + 1).join(" "), "end", "+input"); // 光标处插入 indentUnit 个空格
}
}
}
5)选中单词后,其他相同单词也高亮
需要引入如下文件并增加 option 配置:
import 'codemirror/addon/search/match-highlighter'
highlightSelectionMatches: {
minChars: 2,
trim: true,
style: "matchhighlight",
showToken: false
},
highlightSelectionMatches中 的 showToken 最好配置为 false,否则在在输入的时候,当前还没输入完的单词也会高亮,很难受,如下图所示:
最终效果如下:
这里高亮的样式我是改过的,为了适应这个主题,我重新了 cm-matchhighlight 的样式,修改了它的背景颜色:
.cm-matchhighlight {
background: #848484 !important
}
6)自动补全括号,且光标在括号左右侧时,自动突出匹配的括号
引入如下文件并增加 option 参数:
import 'codemirror/addon/edit/matchbrackets'
import 'codemirror/addon/edit/closebrackets'
autoCloseBrackets: true, // 自动闭合符号
matchBrackets: true, // 在光标点击紧挨{、]括号左、右侧时,自动突出显示匹配的括号 }、]
7)其他有用配置
theme:主题样式,我用的monakai,这个就看个人喜好了
mode:这个很重要,不同的语言要使用对应的mode,这样才能有关键字的高亮!mode列表在中英文手册中可以查
lineWrapping:这个要配置为 false,如果配置为true,样式会比较奇怪,原因未知,或许跟我用的monakai主题有关?有知道的人可以告诉我下。
readOnly:决定是否只读
viewportMargin:一次加载多少行,防止文件过大页面卡死
lineNumbers:显示行数
当然,还有很多有用的功能,不过我暂时够用了,其他也就懒得继续研究了。
更多推荐
所有评论(0)