UNPKG

@leonwerth/vue-diff

Version:

Vue diff

329 lines (304 loc) 9.2 kB
import { diff_match_patch as DiffMatchPatch } from 'diff-match-patch'; import { getDiffType, renderLines, uuid } from './utils'; export interface DiffsProps { name?: string; type?: string; id?: number; key?: string; last?: string; next?: string; uid?: string; } export interface isDiffsProps { chWords: boolean; lineNum: number; type: string; value: string; } export interface DiffGroupProps { name: string; value: number; key: string; cards: Array<DiffsProps>; } const Compare = { // 对比转换回html changeStrToHtml(str: string) { let str1 = str .replace(/\&para\;\<br\>/g, '\n') .replace(/\&gt\;/g, '>') .replace(/\&lt\;/g, '<') .replace(/\&amp\;/g, '&'); // .replace(/list\-style\:none\;/, '') // .replace(/text\-decoration\:none\;/, ''); return str1.substring(6, str1.length - 7); }, // 对比转换html标签 diff_prettyHtml(diffs: any) { var html = []; var pattern_amp = /&/g; var pattern_lt = /</g; var pattern_gt = />/g; var pattern_para = /\n/g; for (var x = 0; x < diffs.length; x++) { var op = diffs[x][0]; // Operation (insert, delete, equal) var data = diffs[x][1]; // Text of change. var text = data .replace(pattern_amp, '&amp;') .replace(pattern_lt, '&lt;') .replace(pattern_gt, '&gt;') .replace(pattern_para, '&para;<br>'); html[x] = text; } return html.join(''); }, // 合并函数不带颜色 concatHTMLWithoutColor( prev: string | undefined, current: string | undefined, ) { var dmp = new DiffMatchPatch(); var d = dmp.diff_main(prev as string, current as string); let html = ''; d.forEach(str => { html += str[1]; }); return html; }, // 合并函数 concatHTML(prev: string | undefined, current: string | undefined) { var dmp = new DiffMatchPatch(); var d = dmp.diff_main(prev as string, current as string); dmp.diff_cleanupSemantic(d); var ds = dmp.diff_prettyHtml(d); // 拿到对比完之后的数组 let html = this.changeStrToHtml(ds); return html; }, // 两屏对比函数 diffScreens( prevHtml: string | any, currentHtml: string | any, id: string, ) { if(!prevHtml && !currentHtml){ console.log('没有获取到要对比的字符串', prevHtml, currentHtml) return } const dmp = new DiffMatchPatch(); const diff = dmp.diff_main(prevHtml, currentHtml); // console.log(diff, '对比结果') dmp.diff_cleanupSemantic(diff); let word = diff .filter(result => getDiffType(result[0]) !== 'removed') .map((result, idx) => { // let t = ''; // if (getDiffType(result[0]) === 'added') { // t = `<span class='modified ${id}'>${result[1]}</span>`; // } else { // t = result[1]; // } return result[1]; }) .join(''); return word; }, // 两屏对比塞入颜色 compareHTML(html1: string, html2: string) { // console.log(Htmlj1.value, Htmlj2.value, 'kkkkkkk') const result = renderLines('split', html1, html2); // console.log(result, '两屏对比结果'); let isDiffs: Array<Array<isDiffsProps>> = []; let newHTML1 = ''; let newHTML2 = ''; result.forEach((res, index) => { let left = res[0]; let id = `pos${index}`; if (!left.chkWords) { // class="vue-diff-cell-${left.type}" newHTML1 += `<span>${left.value}</span>`; } else { let diffText = Compare.diffScreens(res[1].value, left.value, id); // class="vue-diff-cell-${left.type}" id="diff-left-${index}" newHTML1 += `<span>${diffText}</span>`; // 给左边标记添加事件 // setTimeout(() => { // let dom: any = document.getElementById(`diff-left-${index}`) // console.dir(dom) // dom.onclick = function (e: any) { // console.log(diffText) // } // }, 1000) } let right = res[0]; if (!right.chkWords) { // class="vue-diff-cell-${right.type}" newHTML2 += `<span>${right.value}</span>`; } else { let diffText = Compare.diffScreens(right.value, res[1].value, id); // class="vue-diff-cell-added" id="diff-right-${index}" newHTML2 += `<span>${diffText}</span>`; // 给右边标记添加事件 // setTimeout(() => { // let dom: any = document.getElementById(`diff-right-${index}`) // console.dir(dom) // dom.onclick = function (e: any) { // console.log(diffText) // } // }, 1000) } // 计算不同的地方 let i0 = res[0]; let i1 = res[1]; if (i0.type !== i1.type) { const d: any = this.computeTypes(res, index, id); isDiffs = isDiffs.concat(d); } }); const Diffs: any = this.uniqText(isDiffs); return { newHTML1, newHTML2, Diffs }; }, // 去重 uniqText(isDiffs: Array<Array<isDiffsProps>>) { let textArr: Array<string> = []; isDiffs.forEach(item => { let str = JSON.stringify(item); if (!textArr.includes(str)) { textArr.push(str); } }); let newArr: Array<DiffsProps> = []; textArr.forEach(str => { newArr.push(JSON.parse(str)); }); let add = newArr.filter(item => item.type === 'add'); let remove = newArr.filter(item => item.type === 'remove'); let edit = newArr.filter(item => item.type === 'edit'); return { Diffs: newArr, DiffsCount: [ { name: '全部', value: newArr.length, key: 'all', cards: newArr as Array<DiffsProps>, }, { name: '删除', value: remove.length, key: 'remove', cards: remove as Array<DiffsProps>, }, { name: '新增', value: add.length, key: 'add', cards: add as Array<DiffsProps>, }, { name: '修改', value: edit.length, key: 'edit', cards: edit as Array<DiffsProps>, }, ], }; }, // 计算 删除、新增、编辑 不同类的文件 computeTypes(arr: Array<any>, idx: number, id: string) { const dCartInfo: Array<DiffsProps> = []; const dText = this.getDiffArr(arr[0].value, arr[1].value); const clearTag = (nextText: string) => { // // 处理 >< 尖括号标签 let text: string | undefined = nextText; if (nextText.includes('>') && nextText.includes('<')) { let result2 = nextText.match(/\>(.*?)\</g); let result3 = result2?.map(item => { return item.replace(/[\> \<]/g, ''); }); text = result3?.join(''); } return text; }; dText.forEach((dArr, index) => { // 随机id const uid = uuid(); let edit = false; // 新增(1 是新增 新增的上一行是-1 则是编辑) if (dArr[0] === 1) { if (dText[index - 1] && dText[index - 1][0] === -1) { edit = true; dCartInfo.push({ name: '修改', type: 'edit', id: idx, key: id, uid: uid, last: clearTag(dText[index - 1][1]), next: clearTag(dArr[1]), }); } if (!edit) { dCartInfo.push({ name: '新增', type: 'add', id: idx, key: id, uid: uid, last: '', next: clearTag(dArr[1]), }); } } // 删除(-1 是删除 删除的下一行是1 则是编辑) if (dArr[0] === -1) { if (dText[index + 1] && dText[index + 1][0] === 1) { edit = true; dCartInfo.push({ name: '修改', type: 'edit', id: idx, key: id, uid: uid, last: clearTag(dArr[1]), next: clearTag(dText[index + 1][1]), }); } if (!edit) { dCartInfo.push({ name: '删除', type: 'remove', id: idx, key: id, uid: uid, last: '', next: clearTag(dArr[1]), }); } } }); return dCartInfo; //this.doingDate(); }, // 去掉对 html 特殊处理的标签 doingDate(dCartInfo: Array<DiffsProps>) { // 过滤两边没有结果的数据(主要是替换标签导致的) const res = dCartInfo.filter((item: DiffsProps) => item.last || item.next); // 过滤重复数据 const uniqArr: any = []; const diffResult: DiffsProps | any = []; res.forEach((item: DiffsProps | any) => { if (!uniqArr.includes(item.last + item.next + item.type)) { uniqArr.push(item.last + item.next + item.type); diffResult.push(item); } }); // console.log(diffResult, '888888888'); return diffResult; }, getDiffArr(prev: string, current: string) { var dmp = new DiffMatchPatch(); var d = dmp.diff_main(prev as string, current as string); return d; }, }; export default Compare;