【前后内容对比】字符串或纯 HTML 对比 实现思路(1)

简介: 【前后内容对比】字符串或纯 HTML 对比 实现思路(1)

1、目的

  • 当前有个需求 需要 将用户基本 前后内容 修改部分 标识出来

比如 有个页面 需要 这样 (示例,样式都可定制化更改)

  • 绿色表示 添加的内容
  • 删除线 表示 删除部分

网络异常,图片无法展示
|

2、先说 HTML 对比

  • 直接 将两部分 html 直接 对比 , 页面显示 对比结果 非常 舒适

2-1、代码

  • htmldiff.js
!function(){var e,n,t,r,i,f,_,a,o,s,u,h,l,c,d,b,p;o=function(e){return">"===e},s=function(e){return"<"===e},h=function(e){return/^\s+$/.test(e)},u=function(e){return/^\s*<[^>]+>\s*$/.test(e)},l=function(e){return!u(e)},e=function(){return function(e,n,t){this.start_in_before=e,this.start_in_after=n,this.length=t,this.end_in_before=this.start_in_before+this.length-1,this.end_in_after=this.start_in_after+this.length-1}}(),a=function(e){var n,t,r,i,f,_;for(f="char",t="",_=[],r=0,i=e.length;r<i;r++)switch(n=e[r],f){case"tag":o(n)?(t+=">",_.push(t),t="",f=h(n)?"whitespace":"char"):t+=n;break;case"char":s(n)?(t&&_.push(t),t="<",f="tag"):/\s/.test(n)?(t&&_.push(t),t=n,f="whitespace"):/[\w\#@]+/i.test(n)?t+=n:(t&&_.push(t),t=n);break;case"whitespace":s(n)?(t&&_.push(t),t="<",f="tag"):h(n)?t+=n:(t&&_.push(t),t=n,f="char");break;default:throw new Error("Unknown mode "+f)}return t&&_.push(t),_},f=function(n,t,r,i,f,_,a){var o,s,u,h,l,c,d,b,p,g,w,v,k,m,y;for(s=i,o=_,u=0,w={},c=h=m=i,y=f;m<=y?h<y:h>y;c=m<=y?++h:--h){for(k={},d=0,b=(p=r[n[c]]).length;d<b;d++)if(!((l=p[d])<_)){if(l>=a)break;null==w[l-1]&&(w[l-1]=0),v=w[l-1]+1,k[l]=v,v>u&&(s=c-v+1,o=l-v+1,u=v)}w=k}return 0!==u&&(g=new e(s,o,u)),g},d=function(e,n,t,r,i,_,a,o){var s;return null!=(s=f(e,0,t,r,i,_,a))&&(r<s.start_in_before&&_<s.start_in_after&&d(e,n,t,r,s.start_in_before,_,s.start_in_after,o),o.push(s),s.end_in_before<=i&&s.end_in_after<=a&&d(e,n,t,s.end_in_before+1,i,s.end_in_after+1,a,o)),o},r=function(e){var n,t,r,i,f,_;if(null==e.find_these)throw new Error("params must have find_these key");if(null==e.in_these)throw new Error("params must have in_these key");for(r={},n=0,i=(f=e.find_these).length;n<i;n++)for(r[_=f[n]]=[],t=e.in_these.indexOf(_);-1!==t;)r[_].push(t),t=e.in_these.indexOf(_,t+1);return r},_=function(e,n){var t,i;return i=[],t=r({find_these:e,in_these:n}),d(e,n,t,0,e.length,0,n.length,i)},n=function(n,t){var r,i,f,a,o,s,u,h,l,c,d,b,p,g,w,v;if(null==n)throw new Error("before_tokens?");if(null==t)throw new Error("after_tokens?");for(w=g=0,p=[],r={"false,false":"replace","true,false":"insert","false,true":"delete","true,true":"none"},(d=_(n,t)).push(new e(n.length,t.length,0)),a=f=0,h=d.length;f<h;a=++f)"none"!==(i=r[[w===(c=d[a]).start_in_before,g===c.start_in_after].toString()])&&p.push({action:i,start_in_before:w,end_in_before:"insert"!==i?c.start_in_before-1:void 0,start_in_after:g,end_in_after:"delete"!==i?c.start_in_after-1:void 0}),0!==c.length&&p.push({action:"equal",start_in_before:c.start_in_before,end_in_before:c.end_in_before,start_in_after:c.start_in_after,end_in_after:c.end_in_after}),w=c.end_in_before+1,g=c.end_in_after+1;for(v=[],u={action:"none"},o=function(e){return"equal"===e.action&&(e.end_in_before-e.start_in_before==0&&/^\s$/.test(n.slice(e.start_in_before,+e.end_in_before+1||9e9)))},s=0,l=p.length;s<l;s++)o(b=p[s])&&"replace"===u.action||"replace"===b.action&&"replace"===u.action?(u.end_in_before=b.end_in_before,u.end_in_after=b.end_in_after):(v.push(b),u=b);return v},t=function(e,n,t){var r,i,f,_,a,o;for(_=void 0,f=i=0,a=(n=n.slice(e,+n.length+1||9e9)).length;i<a&&(o=n[f],!0===(r=t(o))&&(_=f),!1!==r);f=++i);return null!=_?n.slice(0,+_+1||9e9):[]},p=function(e,n){var r,i,f,_,a;for(_="",f=0,r=n.length;;){if(f>=r)break;if(i=t(f,n,l),f+=i.length,0!==i.length&&(_+="<"+e+">"+i.join("")+"</"+e+">"),f>=r)break;f+=(a=t(f,n,u)).length,_+=a.join("")}return _},(c={equal:function(e,n,t){return n.slice(e.start_in_before,+e.end_in_before+1||9e9).join("")},insert:function(e,n,t){var r;return r=t.slice(e.start_in_after,+e.end_in_after+1||9e9),p("ins",r)},delete:function(e,n,t){var r;return r=n.slice(e.start_in_before,+e.end_in_before+1||9e9),p("del",r)}}).replace=function(e,n,t){return c.delete(e,n,t)+c.insert(e,n,t)},b=function(e,n,t){var r,i,f,_;for(_="",r=0,i=t.length;r<i;r++)f=t[r],_+=c[f.action](f,e,n);return _},(i=function(e,t){var r;return e===t?e:(e=a(e),t=a(t),r=n(e,t),b(e,t,r))}).html_to_tokens=a,i.find_matching_blocks=_,_.find_match=f,_.create_index=r,i.calculate_operations=n,i.render_operations=b,"function"==typeof define?define([],function(){return i}):"undefined"!=typeof module&&null!==module?module.exports=i:"undefined"!=typeof window&&(window.htmldiff=i)}();
复制代码
  • App.vue (放在哪里都可以 )
<div id="app">
    <router-view />
    <span v-html="output"></span>
  </div>
</template>
<script>
import htmldiff from './htmldiff'
// 这个 文件尝试对比 html
export default {
  data() {
    return {
      output: '',
    }
  },
  created() {
    this.getDiffHtml()
  },
  methods: {
    getDiffHtml() {
      let originalHTML = `
    <p>Hello Mr. Wayne, decide what to do:</p>
    <ul>
        <li>Call Alfred</li>
        <li>Take Thalia Al Gul to the cinema</li>
        <li>Save Gotham</li>
    </ul>
    <span>Use the mouse to choose an option.</span>
`
      let newHTML = `
<layout>
    <p>Hello Batman, decide what to do:</p>
<ul>
    <li>Kill The Joker</li>
    <li>Save Thalia Al Gul</li>
    <li>Save Gotham</li>
</ul>
<span>Use the batarang to choose an option.</span>
`
      // Diff HTML strings
      let output = htmldiff(originalHTML, newHTML)
      // Show HTML diff output as HTML (crazy right?)!
      this.output = output
      //   document.body.innerHTML = output
    },
  },
}
</script>
<style>
ins {
  text-decoration: none;
  background-color: green;
}
del {
  text-decoration: line-through;
  /* background-color: gray; */
  color: #555;
}
</style>
复制代码

2-2、效果

网络异常,图片无法展示
|

3、再聊 字符串 对比

  • 很多时候 数据 是 字符串 格式, 如何做前后 对比,此处使用 diff.js

3-1、代码

  • 安装 diff.js npm i diff
  • 以 Home.vue为例
<template>
  <div>
    时代背景:
    <span v-html="display"></span>
  </div>
</template>
<script>
// import { res } from '../diff'
const Diff = require('diff')
export default {
  name: 'Home',
  data() {
    return {
      display: '',
    }
  },
  created() {
    this.myDiff()
  },
  methods: {
    myDiff() {
      // 单词 对比
      const test = JSON.stringify(['912382732138138', 'dadadad', '11111'])
      const other = JSON.stringify([
        '31923921328138',
        'dajdj23838',
        '2123jjjjjada',
        '11111',
      ])
      const diff = Diff.diffWords(test, other),
        display = document.createElement('div'),
        fragment = document.createDocumentFragment()
      diff.forEach((part) => {
        // green for additions, red for deletions
        // grey for common parts
        const color = part.added ? 'green' : part.removed ? '' : ''
        const textDecoration = part.added
          ? 'none'
          : part.removed
          ? 'line-through'
          : ''
        const span = document.createElement('span')
        span.style.backgroundColor = color
        span.style.textDecoration = textDecoration
        span.appendChild(document.createTextNode(part.value))
        fragment.appendChild(span)
      })
      display.appendChild(fragment)
      this.display = display.innerHTML
    },
  },
  components: {},
}
</script>
复制代码

3-2、效果

网络异常,图片无法展示
|

4、小结

  • 两种 方式 对比前后的 修改内容,帮助业务快速对内容进行 操作/审核,非常舒适

5、完整代码github 地址

* github 地址(能点个 star 就太好啦!)

6、参考资料

1、diff Html

2、diff.js


相关文章
|
2月前
|
JavaScript 前端开发
用JavaScript正则表达式匹配对应字符串高亮显示,并过滤掉空格、<、>等HTML节点符号
用JavaScript正则表达式匹配对应字符串高亮显示,并过滤掉空格、<、>等HTML节点符号
|
2月前
|
存储 安全 JavaScript
如何安全的渲染HTML字符串?
如何安全的渲染HTML字符串?
|
11天前
|
JavaScript
js HTML字符串转DOM节点,DOM节点转HTML字符串
js HTML字符串转DOM节点,DOM节点转HTML字符串
9 2
|
2月前
|
JavaScript 搜索推荐 UED
一种将 Vue 组件渲染为 HTML 字符串的技术
【5月更文挑战第8天】Vue 的服务器端渲染(SSR)技术在服务器上将组件渲染为 HTML,提升首屏加载速度和 SEO。优点包括更快的用户体验、更好的搜索引擎优化及减轻客户端负担。然而,SSR也带来服务器压力增大、开发复杂性和额外的构建配置需求。vue-server-renderer 包支持 Vue SSR,但是否采用取决于项目需求和资源。
26 1
|
2月前
|
iOS开发
iOS中如何显示后台返回的带有html标签的富文本字符串
iOS中如何显示后台返回的带有html标签的富文本字符串
33 0
|
2月前
|
Python
python html(文件/url/html字符串)转pdf
python html(文件/url/html字符串)转pdf
25 0
|
2月前
|
前端开发 JavaScript 安全
react如何渲染包含html标签元素的字符串
react如何渲染包含html标签元素的字符串
90 0
|
iOS开发
iOS HTML转字符串
iOS HTML转字符串
93 0
|
JavaScript
vue使用v-html实现一段字符串中关键字(词)高亮效果
vue使用v-html实现一段字符串中关键字(词)高亮效果
188 0