背景
各个公司有各个公司的技术栈,在之前公司强大的前端脚手架的支持下,成功的运用react + ts依赖codemirror,实现了一个在线编辑工具(主要目的是为了增强代码覆盖率的报告展示能力)。后面因为“大环境”的原因,来到了新的公司,并需要在vue的环境下重新造一回轮子。当然我想用最小成本,复用之前大部分的codemirror自定义渲染相关的代码。于是在vue的社区中,找到了一个vue-codemirror的依赖。但是因为语法封装上的差异,并没法一摸一样的使用之前的方式进行复用。通过度娘,找到的信息,又不能完全解决问题,所以仅用此文,来记录这些细节。
vue的lib引用
首先是找到依赖并进行lib导入。这块度娘还是有的。我主要使用的方式如下:
npm install vue-codemirror
在main.js中引入codemirror
import VueCodeMirror from 'vue-codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/idea.css';
import 'codemirror/mode/clike/clike.js';
Vue.use(VueCodeMirror);
之后我们就可以顺利的使用codemirror了。
codemirror https://codemirror.net/5/doc/manual.html
codemirror的renderLine
codemirror的renderLine是一个很强大的自定义渲染代码展示方法。它的内置参数有整个codemirror的实例,进行渲染时某一行的句柄以及某一行的完整dom元素。在我的案例中,主要需要在展示代码的基础上附加代码行的背景色,并为每一行代码添加具体的提交改动时间。
之前直接使用codemirror的方式下,可以直接使用onRenderLine的属性来使用自定义的renderLine方法:
<CodeMirror
className={styles.mirrorCode}
options={
{
mode: 'text/x-java',
theme: 'idea',
lineNumbers: true,
lineWrapping: true,
showCursorWhenSelecting:true,
// viewportMargin: 20,
readOnly:true,
selectionPointer:true,
styleActiveLine: true,
}
}
onRenderLine={(editor:any, line:any, elem:any) =>
this.renderLine(editor, line, elem)}
value={fileContent}
editorDidMount={(editor:any) => this.handleEditMount(editor)}
onChange={(edit:any) => { console.log('内容改动了'); }}
/>
但是在vue-codemirror中没有了这个属性。
<template>
<el-card v-loading="loading">
<h2>{{`${appName} - ${path}`}}</h2>
<codemirror
ref="covCode"
class="mirrorCode"
:options="options"
:value="content"
/>
</el-card>
</template>
找度娘,查codemirror manual文档,最后发现可以通过codemirror的对象进行renderLine事件绑定,从而达到之前react方式的效果。
首先,可以通过组建的创建事件设置全局的codemirror引用:(created,mounted)
this.codemirror = this.$refs.covCode.codemirror;
其次,可以给codemirror绑定renderLine的event事件:
this.codemirror.on("renderLine", this.renderLine);
最后,就是重新把renderline的代码进行编辑就可以了
// 渲染方法
renderLine(editor, line, elem) {
const lineNumber = line.lineNo();
this.gitRender(lineNumber, elem);
this.coverRender(lineNumber, elem);
},
// 针对某一行渲染代码的提交更改情况
gitRender(lineNumber, elem) {
const commit = this.lines[lineNumber];
if (!commit) {
return;
}
const leftNode = document.createElement('span');
leftNode.style = 'padding-right:5px;width:330px;display:inline-block;';
const gitNode = document.createElement('span');
const content = new Date(commit.updateDate).toLocaleString() + " " + commit.author;
gitNode.textContent = this.cutStringByLength(content, 30);
gitNode.style = 'width:260px;display:inline-block;';
leftNode.appendChild(gitNode);
const dt = new Date;
// 新旧代码提醒
if ((dt.getTime() - new Date(commit.updateDate).getTime())
< 24 * 60 * 60 * 1000 * 14) {
const strongNew = document.createElement('strong');
strongNew.textContent = ' New ';
strongNew.style = 'color:red';
gitNode.appendChild(strongNew);
}
if (elem.children[0]) {
elem.insertBefore(leftNode, elem.children[0]);
} else {
elem.appendChild(leftNode);
}
},
// 针对某一行渲染背景颜色
coverRender(lineNumber, elem) {
const status = this.covLines[lineNumber + 1];
if (status && status !== 0) {
switch (status) {
case 1:
elem.setAttribute("style", (elem.getAttribute("style") || '') + "background: rgba(255, 179, 185, 0.42);")
break;
case 2:
elem.setAttribute("style", (elem.getAttribute("style") || '') + "background: rgba(139, 195, 74, 0.51);")
break;
case 3:
elem.setAttribute("style", (elem.getAttribute("style") || '') + "background: rgba(255, 152, 0, 0.43);")
break;
default:
break;
}
}
}
效果图:
最后
通过上述的这种方式,绝大多数数的代码都可以从之前react版本,轻松快捷的转移到vue 上。codemirror在在线编辑这块上确实挺好用,如果有需要可以使用上cdn版本,让前端体验上可以更好。在其他的一些属性,内置对象,内置方法上有需要可以参考manual进行查找,合理使用。