对比 html 的渲染结果

11 条回复
108 次浏览

接上文 对比 html 文档差异

将富文本转换成 html 后,尝试对比修改前后的页面,最开始的方案是对比 html 的 dom 内的文字和样式。
问题在于 html 的样式很灵活,不同的 css 组合起来可能显示效果是一样的。
后面想到新的方法,就是将两段 html 分别渲染成页面,截图对比像素差异,这个有一个类似的实现库 Resemble.js 实现效果代码如下。

image

这个方法的问题在于不如 git 那种文本对比灵活匹配。
目前想不到更好的方法了,求指教。

复制
<!-- 两段 html 渲染对比 -->
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>HTML 渲染图像对比</title>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/resemble.js"></script>
  <script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
  <style>
    #preview1, #preview2 {
      width: 400px;
      height: auto;
      border: 1px solid #ccc;
      margin-bottom: 10px;
    }
    textarea {
      width: 400px;
      height: 150px;
    }
  </style>
</head>
<body>
  <h2>输入两段 HTML 代码进行渲染对比</h2>
  <div>
    <h3>HTML 1</h3>
    <textarea id="html1"><h2 style="background:#eee;padding:6px 10px;margin:0">旧 HTML</h2>
      <div id="oldPane" class="content">
        <h3>旧标题</h3>
        <p>这是一段<strong>原始</strong>文字。</p>
        <ul>
          <li>项 A</li>
          <li>项 B</li>
        </ul>
        <p>测试</p>
      </div></textarea>
    <div id="preview1"></div>
  </div>
  <div>
    <h3>HTML 2</h3>
    <textarea id="html2"><h2 style="background:#eee;padding:6px 10px;margin:0">新 HTML</h2>
      <div id="newPane" class="content">
        <h3>新标题</h3>
        <p>这是一段<strong>修改后</strong>文字。</p>
        <ul>
          <li>项 A</li>
          <li>项 B 已改</li>
          <li>项 C 新增</li>
        </ul>
      </div></textarea>
    <div id="preview2"></div>
  </div>
  <button onclick="renderAndCompare()">渲染并对比</button>
  <h3>差异图:</h3>
  <div id="result"></div>
  <script>
    async function renderAndCompare() {
      const html1 = document.getElementById('html1').value;
      const html2 = document.getElementById('html2').value;

      const preview1 = document.getElementById('preview1');
      const preview2 = document.getElementById('preview2');

      preview1.innerHTML = html1;
      preview2.innerHTML = html2;

      const canvas1 = await html2canvas(preview1);
      const canvas2 = await html2canvas(preview2);

      const img1 = canvas1.toDataURL();
      const img2 = canvas2.toDataURL();

      resemble(img1)
        .compareTo(img2)
        .onComplete(function(data) {
          const diffImage = new Image();
          diffImage.src = data.getImageDataUrl();
          document.getElementById('result').innerHTML = `
            <p>差异百分比:${data.misMatchPercentage}%</p>
          `;
          document.getElementById('result').appendChild(diffImage);
        });
    }
  </script>
</body>
</html>

image

马上来

不太懂前端,帮你顶贴,论坛里有很多前端大佬,希望能帮你解决

大平衡者
Guardian

这个方案也不是很好,万一我只是在列表中间插入一行,那从这个插入的地方开始开始后面全都对不上了:
比如
aa
bb
cg
dc
ed
估计还得从 git diff 那套入手
听起来相当复杂

都听我说!

我这之前有个 xml 在线编辑的一个功能,两个人同时编辑,最终两个人提交两个版本,然后就是像 git 那样两边同时比较

大概得方案是这样做

  1. 刚进来,前端把整个 html 序列化成一个 json 对象,然后发送给后端,存起来.每一个节点都有自己的 id
    2 用户 1 最终提交前本地会在产生一个 json 对象,这个对象包含了用户 1 修改的节点 id 和修改后的内容.用户 2 也是一样的
  2. 对比是 3 个 json 对象,一个是原始的 json 对象,一个是用户 1 修改后的 json 对象,一个是用户 2 修改后的 json 对象.通过对比这三个对象,可以找出哪些节点被修改了,哪些节点被删除了,哪些节点被新增了.
  3. 这个就会产生一个冲突的情况,比如用户 1 修改了节点 A 的内容,用户 2 也修改了节点 A 的内容,这时候就需要人工来解决冲突.可以通过一个界面来展示冲突的节点,让用户选择保留哪个版本或者手动合并两个版本.
  4. 生成的 id 类似规则是 001001001001 这种格式,每个节点的 id 由父节点的 id 加上一个三位数的序列组成.比如根节点的 id 是 001,它的第一个子节点的 id 就是 001001,第二个子节点的 id 就是 001002,以此类推.这样就可以唯一标识每个节点的位置和层级关系.

这个是我知道的做法,剩下的全是前端硬撸出来的

都听我说!
  1. 性能很烂,超过 1 万行的很卡.当时渲染也有技巧,到那一块才会显示那一块的区别.怎么做的不知道

最终的效果跟 Beyond Compare 软件文件对比很像,有差异的地方都是红色,因为有 id 一样,中间的差异都是加空行,把 id 一样的渲染在同一行,

马上来

6 这点用的虚拟列表?但是虚拟列表也有问题, 搜索文本的时候可能搜不到

都听我说!

@corcre 为了最简单解决这个问题,在搜索时添加搜索的是标签还是内容两个选项.

比如你说的文本,json 找到那一行,然后按固定范围渲染就行. 上下多少行都是固定的.

马上来

@diudiuu 能搜索的还好, 以前我们用的虚拟列表用 canvas 渲染的, 别说搜索了, 连复制都复制不了facepalm

都听我说!

@corcre 这个项目当时我们啥都做,就像做了一个自定义的富文本编辑器.
项目上线后,公司申请什么软著,就问这个能干啥.
给的回复就是傻子才用这个软件,脑子不好,我下载个编辑器不香吗.

种子用户
OP

目前我也是树比较的方法,只是没有手动合并和生成 ID 这么严谨。

都听我说!

fake_sad id 这个是客户非要那种对齐的效果,实际难度要比我下面这个例子还要复杂的多.
a b d 都要对齐,没有 id 找不到位置

`
原始
a
b
d

第一个(追加 c)
a
b
c
d

第二个(中间多个空行)
a

b
d

最终对比
a a
(无空行) (有空行)
b b
c
d d

`

发表一个评论

R保持