文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

利用vue对比两组数据差异的可视化组件详解

2024-04-02 19:55

关注

如题,朋友有个这样的需求,感觉挺常见,发出来给大家参考一下

需求:

用el-table展示两组数据,有差异的单元格显示红色,新增的显示整行绿色

大概要点:

根据刚才的要点可以建立一下组件的props:


props: {
  uniqueKey: {
    type: String,
    default: "id"
  },
  dataGroup: {
    type: Array,
    validator: val => val.length === 2
  },
  columns: {
    type: Array,
    required: true
  }
}

唯一id默认为id;columns的格式就按照el-table-column的来,定义为{ label, prop, ... }

组件的基本样式也很简单:


<template>
  <div class="diff-table-container">
    <el-table
      v-for="(data, i) in completedData"
      :key="i"
      :data="data"
      :row-style="markRowStyles"
      :cell-style="markCellStyles"
    >
      <el-table-column v-for="item in columns" :key="`${i}${item.prop}`" align="center" v-bind="item" />
    </el-table>
  </div>
</template>

<style lang="scss" scoped>
.diff-table-container {
  display: flex;
  align-items: flex-start;
  .el-table + .el-table {
    margin-left: 20px;
  }
}
</style>

如上所示,就是把两个表格简单的横向排布。这里的completedData指进行diff处理完成之后的数据,格式和传进来的dataGroup是一样的。markRowStyles和markRowStyles都是el-table提供的,分别指行和列的样式,值为对象或返回一个对象的函数。

接下来定义两个Symbol,之后在diff数据的时候会给数据加上标记,用Symbol做标记可以防止属性名冲突。


data() {
  return {
    DIFF_CELL_KEY: Symbol("diffCells"), // 一个数组,存储有差异的cell属性名
    COMPLETED_KEY: Symbol("completed") // 标记已完成处理
  };
}

然后diff的样式处理也可以直接定下来了。


methods: {
  // 完成处理之后没有标记的,就表示只在一组数据中出现,也就是新增数据
  markRowStyles({ row }) {
    return (
      !row[this.COMPLETED_KEY] && {
        backgroundColor: "#E1F3D8"
      }
    );
  },
  // 根据当前行的唯一key,找到map中缓存的行数据
  // 就是dataGroup[0].find(item => item[uniqueKey] === row[uniqueKey])
  // 然后判断DIFF_CELL_KEY数组中是否包含当前列的属性名
  markCellStyles({ row, column }) {
    const { $_cacheMap, uniqueKey, DIFF_CELL_KEY } = this;
    const _cacheRow = $_cacheMap.get(row[uniqueKey]);
    return (
      _cacheRow &&
      _cacheRow[DIFF_CELL_KEY].includes(column.property) && {
        backgroundColor: "#FDE2E2"
      }
    );
  }
}

最后就是diff的处理了,直接用计算属性去做,处理完成之后返回新数据:


computed: {
  // 处理完成的数据
  completedData({ dataGroup, uniqueKey, columns, DIFF_CELL_KEY, COMPLETED_KEY }) {
    // 这一步不是必要的,根据业务需求来,如果规定不能修改原数据的话就做一下深拷贝
    const _dataGroup = deepClone(dataGroup);
    // Map<string|number, object>,ts不太熟,应该是这么写,其实就是row[unique]: row
    const cacheMap = new Map();
    // 先遍历一次第一组数据,初始化DIFF_CELL_KEY数组,然后存进map中
    for (const _row of _dataGroup[0]) {
      _row[DIFF_CELL_KEY] = [];
      cacheMap.set(_row[uniqueKey], _row);
    }
    // 遍历第二组数据,里面还有一次循环,因为只处理columns里面定义的属性,其他属性不做对比
    for (const _row of _dataGroup[1]) {
      for (const { prop } of columns) {
        // 如果是唯一key就直接跳过
        if (prop === uniqueKey) continue;
        // 从缓存中查找相同的一条数据
        const original = cacheMap.get(_row[uniqueKey]);
        // 如果找不到就说明这条数据是新增的,直接跳过
        if (!original) continue;
        // 否则就在两组数据中打一个标识表示已处理过,不是新增的
        _row[COMPLETED_KEY] = true;
        original[COMPLETED_KEY] = true;
        // 最后对比两个属性值,如果相同就push进DIFF_CELL_KEY数组中
        // 注意这里DIFF_CELL_KEY数组只存在于第一组数据当中
        // 因为只要有差异就会在所有表格中显示,所以不用每一组数据都存
        _row[prop] !== original[prop] && original[DIFF_CELL_KEY].push(prop);
      }
    }
    // 将map存一份到this中,因为会在处理样式的时候用到
    this.$_cacheMap = cacheMap;
    return _dataGroup;
  }
}

完事了,最后贴一下完整代码:


<template>
  <div class="diff-table-container">
    <el-table
      v-for="(data, i) in completedData"
      :key="i"
      :data="data"
      :row-style="markRowStyles"
      :cell-style="markCellStyles"
    >
      <el-table-column v-for="item in columns" :key="`${i}${item.prop}`" v-bind="item" align="center" />
    </el-table>
  </div>
</template>

<script>
function deepClone(val) {
  // 看需求要不要做深拷贝
  return val;
}

export default {
  name: "DiffTable",
  props: {
    uniqueKey: {
      type: String,
      default: "id"
    },
    dataGroup: {
      type: Array,
      validator: val => val.length === 2
    },
    columns: {
      type: Array,
      required: true
    }
  },
  data() {
    return {
      DIFF_CELL_KEY: Symbol("diffCells"),
      COMPLETED_KEY: Symbol("completed")
    };
  },
  computed: {
    completedData({ dataGroup, uniqueKey, columns, DIFF_CELL_KEY, COMPLETED_KEY }) {
      const _dataGroup = deepClone(dataGroup);
      const cacheMap = new Map();
      for (const _row of _dataGroup[0]) {
        _row[DIFF_CELL_KEY] = [];
        cacheMap.set(_row[uniqueKey], _row);
      }
      for (const _row of _dataGroup[1]) {
        for (const { prop } of columns) {
          if (prop === uniqueKey) continue;
          const original = cacheMap.get(_row[uniqueKey]);
          if (!original) continue;
          _row[COMPLETED_KEY] = true;
          original[COMPLETED_KEY] = true;
          _row[prop] !== original[prop] && original[DIFF_CELL_KEY].push(prop);
        }
      }
      this.$_cacheMap = cacheMap;
      return _dataGroup;
    }
  },
  methods: {
    markRowStyles({ row }) {
      return (
        !row[this.COMPLETED_KEY] && {
          backgroundColor: "#E1F3D8"
        }
      );
    },
    markCellStyles({ row, column }) {
      const { $_cacheMap, uniqueKey, DIFF_CELL_KEY } = this;
      const _cacheRow = $_cacheMap.get(row[uniqueKey]);
      return (
        _cacheRow &&
        _cacheRow[DIFF_CELL_KEY].includes(column.property) && {
          backgroundColor: "#FDE2E2"
        }
      );
    }
  }
};
</script>

<style lang="scss" scoped>
.diff-table-container {
  display: flex;
  align-items: flex-start;
  .el-table + .el-table {
    margin-left: 20px;
  }
}
</style>

使用示例:


<template>
  <diff-table :data-group="[oldData, newData]" :columns="tableColumns" />
</template>

<script>
import DiffTable from "./DiffTable.vue";

export default {
  name: "Index",
  components: {
    DiffTable
  },
  data() {
    return {
      oldData: [
        { id: 1, name: "zhangsan1", age: 23, address: "zxczxczxc" },
        { id: 2, name: "zhangsan2", age: 23.5, address: "zxczxczxc" },
        { id: 3, name: "zhangsan34", age: 23, address: "zxczxczxc" },
        { id: 4, name: "zhangsan4", age: 23, address: "zxczxczxc" },
        { id: 5, name: "zhangsan5", age: 23, address: "zxczxczxc" },
        { id: 6, name: "zhangsan5", age: 23, address: "zxczxczxc" }
      ],
      newData: [
        { id: 1, name: "zhangsan1", age: 23, address: "zxczxczxc" },
        { id: 2, name: "zhangsan2", age: 23, address: "zxczxczxc" },
        { id: 4, name: "zhangsan4", age: 23, address: "地址地址地址" },
        { id: 3, name: "zhangsan3", age: 23, address: "zxczxczxc" },
        { id: 5, name: "zhangsan5", age: 23, address: "zxczxczxc" },
        { id: 7, name: "zhangsan5", age: 23, address: "zxczxczxc" },
        { id: 8, name: "zhangsan5", age: 23, address: "zxczxczxc" }
      ],
      tableColumns: [
        { label: "唯一id", prop: "id" },
        { label: "名称", prop: "name" },
        { label: "年龄", prop: "age" },
        { label: "地址", prop: "address" }
      ]
    };
  }
};
</script>

效果预览:

扩展功能TODO:

总结

到此这篇关于利用vue对比两组数据差异的可视化组件的文章就介绍到这了,更多相关vue对比两组数据差异内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯