前言
1.最近公司要求做一个可以类似于git代码比对的页面,然后支持右侧往左侧合并,实现回退版本的功能,使用了codemirror编辑器与diff-match-patch这个插件很好的实现了这个效果,代码可直接复用
实现效果
1.运行命令下载
//运行命令 下载依赖
npm install diff-match-patch -S
npm install codemirror
2.在项目中使用
不多说了,代码中皆有注释,且代码可直接复用,只要求说一点就是,获取最后左侧编辑器内的代码从他的实例里面是拿不到的,且初始化下方的方法,是为了获取当前有多少个差异地方的数量,放在右上角进行展示的,每次点击箭头都会保留剩余的差异数量,获取左侧修改后的编辑器内容,需要调用方法且可获得编辑器内容 ↓↓↓↓↓↓↓↓
const newStr = this.HisCode.edit.getValue();
CSS类中我改动了他的样式,也是借鉴其他大佬的
<template>
<div class="compareClass">
<div ref="CodeMirror"></div>
</div>
</template>
<script>
import CodeMirror from 'codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/addon/merge/merge.js';
import 'codemirror/addon/merge/merge.css';
import DiffMatchPatch from 'diff-match-patch';
import {
CstMixin,
} from 'boot/mixins/cst';
window.diff_match_patch = DiffMatchPatch;
window.DIFF_DELETE = -1;
window.DIFF_INSERT = 1;
window.DIFF_EQUAL = 0;
export default {
name: 'CodeMirror',
mixins: [CstMixin],
props: {
codeId: {
type: String,
defualt: '',
},
currentData: {
type: Object,
defualt: {},
},
},
data() {
return {
historyCode: '',
currentCode: '',
HisCode: null,
divide: '',
};
},
created() {
},
mounted() {
this.showLoading();
if (this.currentData) {
this.currentCode = `${this.currentData.template.value}\n//This is used to separate the code\n${this.currentData.js.value}\n//This is used to separate the code${this.currentData.css.value}`;
}
this.$nextTick(() => {
this.getTemplateCode();
});
},
methods: {
getTemplateCode() {
this.$axios.get(`xxxxxxxxxxxxid=${this.codeId}`).then((r) => {
if (r.code === 200 && r.result) {
this.hideLoading();
const obj = r.result;
this.historyCode = `${JSON.parse(obj.html).value}\n//This is used to separate the code\n${JSON.parse(obj.js).value}\n//This is used to separate the code${JSON.parse(obj.css).value}`;
setTimeout(() => {
this.initUI();
}, 500);
}
}).finally(() => {
this.hideLoading();
});
},
backCurrCode() {
const newStr = this.HisCode.edit.getValue();
const [template, js, cssValue] = newStr.split('//This is used to separate the code');
const codeData = {
formMixin: false,
template: {
value: template.trim(), key: 'template', mode: 'text/x-vue', tab: '模板',
},
js: {
value: js.trim(), key: 'js', mode: 'text/javascript', tab: '代码',
},
css: {
value: cssValue.trim(), key: 'css', mode: 'text/css', tab: '样式',
},
};
this.$emit('getNewData', codeData);
},
// 初始化
initUI() {
const target = this.$refs.CodeMirror;
target.innerHTML = '';
this.HisCode = CodeMirror.MergeView(target, {
value: this.currentCode, // 当前内容
orig: this.historyCode, // 历史版本
origLeft: null,
lineNumbers: true, // 显示行号
indentUnit: 3, // 缩进吧
mode: 'html', // 视图文件格式
highlightDifferences: true, // 高亮
styleActiveLine: true, // 选中的样式
connect: 'align', // 居中方式
theme: 'cobalt', // 视图样式
readOnly: false, // 只读 不可修改
});
this.$nextTick(() => {
// 获取箭头数量
const elements = document.getElementsByClassName('CodeMirror-merge-copy');
this.$emit('getDiff', elements.length);
// 只能通过父容器事件委托来点击
const parentElement = document.getElementsByClassName('CodeMirror-merge-copybuttons-right');
parentElement[0].addEventListener('click', (event) => {
if (event.target.classList.contains('CodeMirror-merge-copy')) {
this.$emit('getDiff', elements.length - 1);
}
});
});
},
},
};
</script>
<style lang="scss">
.compareClass {
height: 100%;
overflow-y: hidden;
overflow-x: auto;
.CodeMirror-merge {
display: flex;
}
//.CodeMirror-linenumber {
// left: -32px !important;
//}
.CodeMirror-merge, .CodeMirror-merge .CodeMirror {
height: 100vh;
}
.CodeMirror-merge-2pane .CodeMirror-merge-pane {
height: 100%;
}
.CodeMirror-merge-r-chunk {
background: rgba(30, 144, 255, 0.5);
}
.CodeMirror-merge-r-chunk-start {
border-top: 1px solid dodgerblue;
}
.CodeMirror-merge-r-chunk-end {
border-bottom: 1px solid dodgerblue;
}
.CodeMirror-merge-r-connect {
fill: rgba(30, 144, 255, 0.5);
stroke: rgba(30, 144, 255, 0.5);
stroke-width: 1px;
}
.CodeMirror-merge-l-chunk {
background: rgba(30, 144, 255, 0.5);
}
.CodeMirror-merge-l-chunk-start {
border-top: 1px solid dodgerblue;
}
.CodeMirror-merge-l-chunk-end {
border-bottom: 1px solid dodgerblue;
}
.CodeMirror-merge-l-connect {
fill: rgba(30, 144, 255, 0.5);
stroke: rgba(30, 144, 255, 0.5);
stroke-width: 1px;
}
.CodeMirror-merge-l-chunk {
background: rgba(30, 144, 255, 0.5);
}
.CodeMirror-merge-r-chunk {
background: rgba(30, 144, 255, 0.5);
}
.CodeMirror-merge-l-chunk-start {
border-top: 1px solid dodgerblue;
}
.CodeMirror-merge-r-chunk-start {
border-top: 1px solid dodgerblue;
}
.CodeMirror-merge-l-chunk-end {
border-bottom: 1px solid dodgerblue;
}
.CodeMirror-merge-r-chunk-end {
border-bottom: 1px solid dodgerblue;
}
}
</style>
3.如果需要反转过来(需求类似于git那种左改右)因为是只支持左侧修改,所以可以通过样式进行翻转,实现效果
上代码
//反转样式
.CodeMirror-merge-right {
left: 0px
}
.CodeMirror-merge-gap {
left: 47%;
}
.CodeMirror-merge-editor {
position: absolute;
right: 0;
}
.CodeMirror-merge-copy {
transform: rotateY(180deg);
left: 10px !important;
}