如何實現 github 代碼比對效果?

背景

背景是我想要做一個類似於 github 的代碼比對的效果,方便我後續做表單更新的時候,通過 Json View 可以很清晰的看到變更,所以需要做這麼一個東西,看了一下市面上有不少比較完整的插件,所以就選擇了其中的一種來實現,整體做下來還是很快的。

本篇文章主要聚焦於 “實現”,後續可能會寫一篇文章去聊diff代碼比對的原理

技術方案

「技術選型:jsDiff + diff2html」

Html Demo

爲了驗證這個方案的可行性,我用 HTML + JS 做了一個 MVP 版本,代碼和配置還有最後的實現細節效果都如下,整體感覺沒啥問題。

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="UTF-8">  
    <title>diff2html Example</title>  
    <!-- 引入diff2html的CSS樣式 -->  
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css">  
    <!-- 引入diff2html的JavaScript庫 -->  
    <script src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>  
    <!-- 引入 jsdiff 的JavaScript庫 -->  
    <script src="https://cdn.jsdelivr.net/npm/diff/dist/diff.min.js"></script>  
</head>  
<body>  
    <!-- 用於顯示差異的容器 -->  
    <div id="diff-output"></div>  
  
    <script>  
        // 差異字符串(通常通過diff算法生成)  
        // 定義兩個JSON對象(作爲示例)  
        const obj1 = { a: 1, b: 2, c: { d: 3 } };  
        const obj2 = { a: 1, b: 3, c: { d: 4 } };  
  
        // 將JSON對象轉換爲字符串進行比較  
        const text1 = JSON.stringify(obj1, null, 2);  
        const text2 = JSON.stringify(obj2, null, 2);  
  
        // 頁面加載完成後執行  
        document.addEventListener('DOMContentLoaded'function() {  
            // 獲取顯示差異的DOM元素  
            var targetElement = document.getElementById('diff-output');  
            
            const diffOutput = Diff.createTwoFilesPatch(  
                'text1.json', // 左側文件名(僅用於標識)  
                'text2.json', // 右側文件名(僅用於標識)  
                text1,  
                text2,  
                '', // 補丁標題(可選)  
                '' // 補丁標題前綴(可選)  
            );  
  
            // 初始化diff2htmlUI並配置  
            var configuration = {  
                drawFileList: true,       // 是否在差異之前顯示文件列表  
                fileListToggle: false,    // 是否允許切換文件列表的顯示  
                fileListStartVisible: false, // 文件列表是否初始時可見  
                matching: 'lines',        // 匹配級別:行  
                outputFormat: 'side-by-side', // 輸出格式:並排顯示  
                synchronizedScroll: true, // 同步滾動(並排模式)  
                highlight: true,          // 是否高亮顯示代碼  
                renderNothingWhenEmpty: false // 如果沒有差異,是否渲染空內容  
            };  
  
            // 創建並繪製diff  
            var diff2htmlUi = new Diff2HtmlUI(targetElement, diffOutput, configuration);  
            diff2htmlUi.draw();  
            diff2htmlUi.highlightCode();  
        });  
    </script>  
</body>  
</html>

「實現效果:」

React 中使用

只實現一個 HTML DEMO 肯定遠遠不夠,我們需要實際落地的話,就得使用 React 來實現。

  1. 下載相關依賴
yarn diff
yarn diff2html
  1. 需要關注一下引入路徑:不僅僅是處理 diff 文件的引入路徑,diff 的樣式的引入路徑也同樣需要關注,可以簡單看看,列舉如下:
import { createTwoFilesPatch } from 'diff';
import { Diff2HtmlUI } from 'diff2html/lib/ui/js/diff2html-ui';
import 'highlight.js/styles/googlecode.css';
import 'diff2html/bundles/css/diff2html.min.css';
  1. 使用設計好的組件
<DiffComponent
 prevData={code1}
 curData={code2}
 prevFileName={code1Name}
 curFileName={code2Name}
/>

這裏的話其實還值得一提:可以在這裏結合Modal/DrawerDiffComponent封裝一下,當然封裝的過程少不了改組件本身的樣式,因爲常見的使用位置是在一個頁面上,但我們有些常見是需要封裝在 Modal 和 Drawer 裏面的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/lqNO9W6VsYqEwbvmy7rePQ