vue3+diff简单实现对比差异工具组件

结果图

背景

某天要给管理后台的数据配置添加一个审核功能,为了更好的审核,就需要看到数据差异,于是就要开发一款对比差异的页面

调研

  1. 调研有没有现成的组件
  2. 评估自研成本(有AI的加入,成本大幅度降低)

现成的组件感觉有点一般,于是我打算自研,用的是diffdiffChars功能,因为要精确到字符级 ,如果是行级,可以用diffLines,更简单

diffChars需要自己还原原来的数据,最重要的还是他的精度高,可以做字符级的高亮,他的数据结构参考

json 复制代码
[
    {
        "count": 17,
        "added": false,
        "removed": false,
        "value": "{\n  \"name\": \"Alic"
    },
    ....
]

代码

技术栈:vue3、unocss

子组件--Diff.vue

html 复制代码
<script lang="ts" setup>
import type { Change } from 'diff'
import { diffChars } from 'diff'

const props = defineProps<{
  oldData: unknown
  newData: unknown
}>()

const oldStr = computed(() => `${JSON.stringify(props.oldData, null, 2)}\n`)
const newStr = computed(() => `${JSON.stringify(props.newData, null, 2)}\n`)

const diffCharList = computed<Change[]>(() => diffChars(oldStr.value, newStr.value))

interface Segment {
  text: string
  added?: boolean
  removed?: boolean
}

function buildLines() {
  const oldLines: { segments: Segment[]; changed: boolean }[] = []
  const newLines: { segments: Segment[]; changed: boolean }[] = []

  const oldCurrent: Segment[] = []
  const newCurrent: Segment[] = []

  const pushLine = () => {
    oldLines.push({
      segments: [...oldCurrent],
      changed: oldCurrent.some((s) => s.removed),
    })
    newLines.push({
      segments: [...newCurrent],
      changed: newCurrent.some((s) => s.added),
    })
    oldCurrent.length = 0
    newCurrent.length = 0
  }

  diffCharList.value.forEach((part) => {
    const lines = part.value.split(/(?<=\n)/)
    lines.forEach((line, i) => {
      const isNewLine = line.endsWith('\n')

      if (part.added) {
        newCurrent.push({ text: line, added: true })
        if (isNewLine) pushLine()
      } else if (part.removed) {
        oldCurrent.push({ text: line, removed: true })
        if (isNewLine) pushLine()
      } else {
        oldCurrent.push({ text: line })
        newCurrent.push({ text: line })
        if (isNewLine) pushLine()
      }
    })
  })

  if (oldCurrent.length || newCurrent.length) pushLine()

  return { oldLines, newLines }
}

const { oldLines, newLines } = computed(() => buildLines()).value
</script>

<template>
  <div class="font-mono text-14 lh-32 flex overflow-auto b b-gray-300 bg-white">
    <!-- 旧数据 -->
    <div class="flex-1 p-4 b-r b-gray-300 overflow-x-auto">
      <div
        v-for="(line, index) in oldLines"
        :key="'old-' + index"
        :class="{
          'bg-red-100': line.changed,
        }"
        class="whitespace-pre-wrap"
      >
        <template v-for="(segment, i) in line.segments" :key="i">
          <span
            :class="{
              'bg-red-300 line-through': segment.removed,
            }"
          >
            {{ segment.text }}
          </span>
        </template>
      </div>
    </div>
    <!-- 新数据 -->
    <div class="flex-1 p-4 overflow-x-auto">
      <div
        v-for="(line, index) in newLines"
        :key="'new-' + index"
        :class="{
          'bg-green-100': line.changed,
        }"
        class="whitespace-pre-wrap"
      >
        <template v-for="(segment, i) in line.segments" :key="i">
          <span :class="segment.added ? 'bg-green-300' : ''">
            {{ segment.text }}
          </span>
        </template>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped></style>

父组件

html 复制代码
<Diff :old-data="diffObj.oldData" :new-data="diffObj.newData" />

  diffObj.value.oldData = {
    name: 'Alice',
    age: 25,
    address: {
      city: 'New York',
      zip: '10001',
    },
    tags: ['developer', 'frontend'],
    text: 'hello world fsdkafjs撒放假就疯狂拉萨大家疯狂了发啥地方撒的',
    text2: 'hello world fsdkafjs撒放假就疯狂拉萨大家疯狂的发啥地方撒的',
  }
  diffObj.value.newData = {
    name: 'Alicia', // 修改
    age: 26, // 修改
    address: {
      city: 'San Francisco', // 修改
      zip: '94105', // 修改
    },
    tags: ['developer', 'fullstack'], // 修改数组项
    text: 'hello world fsdkafjs撒放假就疯狂拉萨大家疯狂了发啥地方撒的',
    text2: 'hello world fsdkafjs撒放假就疯狂拉萨大家疯狂了发啥地方撒的',
    active: true, // 新增字段
  }
相关推荐
2501_915918412 小时前
Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
前端·低代码·ios·小程序·uni-app·编辑器·iphone
程序员的世界你不懂2 小时前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
索迪迈科技2 小时前
网络请求库——Axios库深度解析
前端·网络·vue.js·北京百思可瑞教育·百思可瑞教育
gnip2 小时前
JavaScript二叉树相关概念
前端
attitude.x3 小时前
PyTorch 动态图的灵活性与实用技巧
前端·人工智能·深度学习
β添砖java3 小时前
CSS3核心技术
前端·css·css3
空山新雨(大队长)4 小时前
HTML第八课:HTML4和HTML5的区别
前端·html·html5
猫头虎-前端技术4 小时前
浏览器兼容性问题全解:CSS 前缀、Grid/Flex 布局兼容方案与跨浏览器调试技巧
前端·css·node.js·bootstrap·ecmascript·css3·媒体
阿珊和她的猫4 小时前
探索 CSS 过渡:打造流畅网页交互体验
前端·css