基于diff2html实现浏览器类git文本对比效果

需求场景

内部自研了一套内容管理系统,可以通过Web页面在线修改内容。为了方便对比修改前后差异点,我们需要在Web页面开发一个类似git对比的组件,最终效果如下:

image.png

实现方案

我们采用的是Java后台+diff2html前端组件的方案实现的本功能。

diff2html

diff2html是一套渲染类似git文本对比的组件,GitHub地址:https://github.com/rtfpessoa/diff2html

下面是组件官方的一套基于HTML+Javascript的代码实现Demo:

<!doctype html>
<html lang="en-us">
  <head>
    <meta charset="utf-8" />
    <!-- Make sure to load the highlight.js CSS file before the Diff2Html CSS file -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css" />
    <link
      rel="stylesheet"
      type="text/css"
      href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"
    />
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
  </head>
  <script>
    const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;

    document.addEventListener('DOMContentLoaded', function () {
      var targetElement = document.getElementById('myDiffElement');
      var configuration = {
        drawFileList: true,
        fileListToggle: false,
        fileListStartVisible: false,
        fileContentToggle: false,
        matching: 'lines',
        outputFormat: 'side-by-side',
        synchronisedScroll: true,
        highlight: true,
        renderNothingWhenEmpty: false,
      };
      var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
      diff2htmlUi.draw();
      diff2htmlUi.highlightCode();
    });
  </script>
  <body>
    <div id="myDiffElement"></div>
  </body>
</html>

将内容拷贝到任意html中,直接运行,能看到如下效果:

image.png

其实从渲染结果来看,diff2html符合我们最终的预期。但上面只是一个示例,const diffString定义的是常量,我们需要寻找生成diffString变量的方案。

如何生成diffString

diff2html官网关于diffString格式的描述如下:

diff2html accepts the text contents of a unified diff or the superset format git diff (https://git-scm.com/docs/git-diff) (not combined or word diff). To provide multiples files as input just concatenate the diffs (just like the output of git diff).

其意思很明确:diffString等同于git unified diff,类似于git的diff生成效果。我们可以使用git diff特性来生成差异文件。

Springboot生成git unified diff

我们尝试在Springboot下,使用Java程序执行服务器上的git diff命令,代码如下:

    @RequestMapping("/gitdiff")
    @ResponseBody
    public ResultObject gitdiff() throws Exception{

        String file1 = "D:\\Develop\\Workspace\\Workspace_ctpstudio\\v5\\a.txt";
        String file2 = "D:\\Develop\\Workspace\\Workspace_ctpstudio\\v5\\b.txt";

        // 假设 git 命令在系统的 PATH 环境变量中
        String[] command = {"git", "diff", "--no-index", file1, file2};

        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.redirectErrorStream(true); // 合并标准输出和标准错误

        try {
            Process process = processBuilder.start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            StringBuilder output = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                output.append(line).append("\n");
            }
            int exitCode = process.waitFor();
            System.out.println("Exited with error code : " + exitCode);
            return ResultObject.success(output.toString());
        } catch (Exception e) {
            return ResultObject.fail("Error occurred while executing git diff command."+e.getMessage());
        }
    }

最后为了让前端能获取Springboot Web服务的diff数据,我们可以在html前端通过ajax获取结果数据,前端最终改造代码如下:

<!-- 引入JQuery cdnjs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    document.addEventListener('DOMContentLoaded', function () {
        var url = window.location.href;
        var contextPath = url.substring(0, url.indexOf('/', 8));
        $.ajax({
            url: contextPath+"/restdemo/gitdiff",
            type: 'GET',
            cache: false,
            dataType: 'json',
            success: function (data) {
                console.log(data);
                if (data.code == 200) {
                    var diffString = data.data;
                    var targetElement = document.getElementById('myDiffElement');
                    var configuration = {
                        drawFileList: true,
                        fileListToggle: false,
                        fileListStartVisible: false,
                        fileContentToggle: false,
                        matching: 'lines',
                        outputFormat: 'side-by-side',
                        synchronisedScroll: true,
                        highlight: true,
                        renderNothingWhenEmpty: false,
                    };
                    var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
                    diff2htmlUi.draw();
                    diff2htmlUi.highlightCode();
               }
            },
            error: function (xhr, status, error) {
                console.log(error);
            }
        });
        
    });
</script>

其它

如果发现页面显示出现了横向滚动条,可以尝试设置div渲染的max-width,如前面demo所示,<div id="myDiffElement">用于承载显示区域,可以在这个dom增加style为<div id="myDiffElement" style="max-width: 1024px">,或者js动态设置宽度。

总结

要实现文本对比并在浏览器中可视化渲染,需要完成如下两步:
第一步:服务器安装git,并使用git diff命令生成git unified diff文本结果
第二步:前端获取git unified diff文本,并使用diff2html前端组件渲染结果到Web页面

总的来说,实现还是很简单的,小小总结,希望对大家有帮助。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容