js 使用 htmldiff 使用 html文档对比

您所在的位置:网站首页 两个文档文字进行对比怎么弄 js 使用 htmldiff 使用 html文档对比

js 使用 htmldiff 使用 html文档对比

2024-06-29 08:03| 来源: 网络整理| 查看: 265

话不多说先贴js

/**  * 文本差异化比对工具,用于比对两段文本之间所存在的差异  */ (function () {   var root = self   /**    * 匹配描述块,一个用来表示相同内容块在新旧文档内位置的描述对象    * @param {Number} startInOld [相同部分在旧文档中的起始位置]    * @param {Number} startInNew [相同部分在新文档中的起始位置]    * @param {Number} size       [相同部分的连续词元个数]    */   var Match = function (startInOld, startInNew, size) {     this.size = size     this.startInOld = startInOld     this.startInNew = startInNew     this.endInOld = this.startInOld + this.size     this.endInNew = this.startInNew + this.size   }   /**    * 操作单元,一个操作单元描述了在具体位置所要    * 执行的具体操作(如:insert、delete、equal与replace)    * @param {Function} action    * @param {Number}   startInOld [相同部分在旧文档中的起始位置]    * @param {Number}   endInOld   [相同部分在旧文档中的结束位置]    * @param {Number}   startInNew [相同部分在新文档中的起始位置]    * @param {Number}   endInNew   [相同部分在新文档中的结束位置]    */   var Operation = function (action, startInOld, endInOld, startInNew, endInNew) {     this.action = action     this.endInOld = endInOld     this.endInNew = endInNew     this.startInOld = startInOld     this.startInNew = startInNew   }   /**    * 将HTML解析成单词列表    * 例: Hello World  ---> [""," ", "Hello", " ", "World", " ", ""]    * @param  {String}         html    * @return {Array}    */   var convertHtml2Words = function (html) {     return html.match(/]+>|[^|\w]|\w+\b|\s+/mg)   }   /**    * 差异对比构建类    * @param {String} oldVersion 老文档    * @param {String} newVersion 新文档    */   var DiffBuilder = function (oldVersion, newVersion, type) {     this.oldVersion = oldVersion     this.newVersion = newVersion     this.type = type     this.operation = null     this.wordIndices = {}     this.oldWords = []     this.newWords = []     this.content = []   }   DiffBuilder.prototype = {     build: function () {       var sd = new Date()       this.splitInputs2Words()       this.indexNewWords()       this.operations = this.getOperations()       this.performOperation()       // '[耗时:' + (new Date() - sd) + '毫秒]' +       return this.content.join('')     },     performOperation: function () {       var opt       for (var i = 0, len = this.operations.length; i < len; i++) {         opt = this.operations[i]         this.operation = opt         opt.action.call(this, opt)       }     },     /**        * 将传入的文本切割成词元        */     splitInputs2Words: function () {       this.oldWords = convertHtml2Words(this.oldVersion)       this.newWords = convertHtml2Words(this.newVersion)     },     /**        * 构建一个newWords队列对应的索引表        * 例如:        * this.newWords = ["", " ", "Hello", " ", "World", " ", ""];        *        * 构建成--->        *        * this.wordIndices = {        *     ""   : [0],        *     " "     : [1, 3, 5]        *     "Hello" : [2],        *     "World" : [4],        *     ""  : [6]        * };        */     indexNewWords: function () {       var newWords = this.newWords       var wordIndices = this.wordIndices       var key; var len = newWords.length       var toString = Object.prototype.toString       for (var i = 0; i < len; i++) {         key = newWords[i]         if (toString.call(wordIndices[key]) !== '[object Array]') {           wordIndices[key] = []         }         wordIndices[key].push(i)       }     },     /**        * 将文档抽象为操作描述队列        * 例如:[euqal, insert, equal],一篇文档可以被抽象为由多个        * “操作命令与位置信息”组成的操作队列;        * @return {Array}        */     getOperations: function () {       var optInOld = 0       var optInNew = 0       var operations = []       var match, action       var matchStartsInOld       var matchStartsInNew       var matchs = this.matchingBlocks()       matchs.push(new Match(this.oldWords.length, this.newWords.length, 0))       for (var i = 0, len = matchs.length; i < len; i++) {         action = null         match = matchs[i]         matchStartsInOld = (optInOld === match.startInOld)         matchStartsInNew = (optInNew === match.startInNew)         if (!matchStartsInOld && !matchStartsInNew) {           action = this.replace         } else if (matchStartsInOld && !matchStartsInNew && this.type === 'add') {           action = this.insert         } else if (!matchStartsInOld && matchStartsInNew && this.type === 'delete') {           action = this.del         }         if (action) {           operations.push(new Operation(action, optInOld, match.startInOld, optInNew, match.startInNew))         }         if (match.size) {           operations.push(new Operation(this.equal, match.startInOld, match.endInOld, match.startInNew, match.endInNew))         }         optInOld = match.endInOld         optInNew = match.endInNew       }       return operations     },     /**        * 获取一个用于描述新旧文档内全部相同内容的匹配描述列表        * @return {Array} 文档匹配描述列表        */     matchingBlocks: function () {       var matchingBlocks = []       this.findMatchingBlocks(0, this.oldWords.length, 0, this.newWords.length, matchingBlocks)       return matchingBlocks     },     /**        * 递归查找匹配项        * @param  {Number} startInOld        * @param  {Number} endInOld        * @param  {Number} startInNew        * @param  {Number} endInNew        * @param  {Array} matchingBlocks        */     findMatchingBlocks: function (startInOld, endInOld, startInNew, endInNew, matchingBlocks) {       var match = this.findMatch(startInOld, endInOld, startInNew, endInNew)       if (!match) {         return       }       if (startInOld < match.startInOld && startInNew < match.startInNew) {         this.findMatchingBlocks(startInOld, match.startInOld, startInNew, match.startInNew, matchingBlocks)       }       matchingBlocks.push(match)       if (match.endInOld < endInOld && match.endInNew < endInNew) {         this.findMatchingBlocks(match.endInOld, endInOld, match.endInNew, endInNew, matchingBlocks)       }     },     /**        * 从指定位置开始查询第一块匹配的文本块        * @param  {Number} startInOld        * @param  {Number} endInOld        * @param  {Number} startInNew        * @param  {Number} endInNew        */     findMatch: function (startInOld, endInOld, startInNew, endInNew) {       var bestMatchInOld = startInOld       var bestMatchInNew = startInNew       var bestMatchSize = 0       var matchLengthAt = {}       var newMatchLengthAt       var newMatchLength, wordIndexList, matchIndex, len       for (var idxOld = startInOld; idxOld < endInOld; idxOld++) {         newMatchLengthAt = {}         wordIndexList = this.wordIndices[this.oldWords[idxOld]]         len = wordIndexList ? wordIndexList.length : 0         for (var i = 0; i < len; i++) {           matchIndex = wordIndexList[i]           if (matchIndex < startInNew) {             continue           }           if (matchIndex >= endInNew) {             break           }           newMatchLength = (matchLengthAt[matchIndex - 1] || 0) + 1           newMatchLengthAt[matchIndex] = newMatchLength           if (newMatchLength > bestMatchSize) {             bestMatchInOld = idxOld - newMatchLength + 1             bestMatchInNew = matchIndex - newMatchLength + 1             bestMatchSize = newMatchLength           }         }         matchLengthAt = newMatchLengthAt       }       return bestMatchSize ? new Match(bestMatchInOld, bestMatchInNew, bestMatchSize) : null     },     insert: function (opt, tagCls) {       this.insertTag('span', 'diffins', this.newWords.slice(opt.startInNew, opt.endInNew))     },     del: function (opt, tagCls) {       this.insertTag('span', 'diffdel', this.oldWords.slice(opt.startInOld, opt.endInOld))     },     equal: function (opt) {       this.content = this.content.concat(this.newWords.slice(opt.startInNew, opt.endInNew))     },     replace: function (opt) {       if (this.type === 'add') {         this.insert(opt, 'diffmod')       } else if (this.type === 'delete') {         this.insert(opt, 'diffmod')       }     },     /**        * 添加标签        * @param  {String} tagName        * @param  {String} cssCls        * @param  {String} words        */     insertTag: function (tagName, cssCls, words) {       var nonTags       var that = this       console.log(words)       while (words.length) {         // 获取words内“连续”的非标签字符         nonTags = this.extractConsecutiveWords(words, true)         if (nonTags.length) {           this.content.push(             this.warpText(nonTags.join(''), tagName, cssCls))         }         if (words.length) {           // 获取words内“连续”的标签字符           this.content = this.content.concat(             this.extractConsecutiveWords(words, false))         }       }     },     /**        * 获取words内连续的“文本”或“标签”        * @param  {Array} words        * @param  {Boolean} isTag        * @return {Array}        */     extractConsecutiveWords: function (words, isTag) {       var idxOfFirstTag = null       for (var i = 0, len = words.length; i < len; i++) {         // 注:是取判定条件的前一位         if (this.isTag(words[i]) == isTag) {           idxOfFirstTag = i           break         }       }       return words.splice(0, idxOfFirstTag !== null ? idxOfFirstTag : words.length)     },     warpText: function (text, tagName, cssCls) {       if (this.type === 'add') {         if (cssCls !== 'diffdel') {           return ` ${text} `         }       }     },     isOpeningTag: function (item) {       return /^\s*]+>\s*$/ig.test(item)     },     isClosingTag: function (item) {       return /^\s*]+>\s*$/ig.test(item)     },     isTag: function (item) {       return this.isOpeningTag(item) ? 1 : this.isClosingTag(item) ? 2 : 0     }   }   root.getHTMLDiff = function (oldVersion, newVersion, type) {     return new DiffBuilder(oldVersion, newVersion, type).build()   }   /**    * 针对高级浏览器开启webWorker支持    */   if (typeof postMessage === 'function') {     onmessage = function (evt) {       var data = evt.data       var diff = getHTMLDiff(data.oldVersion, data.newVersion, data.type)       postMessage(diff)     }   } })()

  有自定义对比需求的在  warpText  方法里面改

使用方法

import './htmldiff' export default { props: { leftText: { type: String, default: '' }, rightText: { type: String, default: '' } }, mounted () { this.$nextTick(() => { setTimeout(() => { this.getDiff() this.getDiff2() }, 100) }) }, methods: { getDiff () { var diff = this.$refs.newT var oldT = this.leftText var newT = this.rightText diff.innerHTML = getHTMLDiff(oldT, newT, 'add') }, getDiff2 () { var diff = this.$refs.oldT var newT = this.leftText var oldT = this.rightText diff.innerHTML = getHTMLDiff(oldT, newT, 'delete') } } }

  方法就是   getHTMLDiff

效果:

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3