新旧节点对比与更新:differNodes

简介: 新旧节点对比与更新:differNodes

一、前言

1688269112943.png


工作中遇到这么一个功能,拖动了一些节点,放置在一个数组 currentNodes 中,然后进行下一步的处理。

当对拖动的那些节点进行删除、复制、撤销、重置等操作时,currentNodes 必然发生一些改变,这些改变可以是:

1. 新节点的添加(新 ID 的加入)

2. 旧节点的更新(版本切换)

3. 旧节点的删除(旧 ID 的删除)

我们需要对比新旧节点列表中的值,当其中的值发生变化时,找出需要删除的节点以及需要添加的节点,由于不变的节点中有我们设置好的配置,因此还要保证这些节点不可发生变动。

  1. 节点的结构如下:
const node = {
  nodeId: 'node_1',
  versionId: 'v1'
}
  1. 节点列表的结构如下:
const nodeList = [
  {nodeId: 'node_1', versionId: 'v1'},
  {nodeId: 'node_2', versionId: 'v1'},
  {nodeId: 'node_3', versionId: 'v1'},
]

根据这个结构,只要节点的 id 或 versionId 变化时,就更新。

二、情况分析

  1. 怎么处理这个问题?准备几个数组:
  • oldList:上一次拖拽产生的节点列表,由 currentNodes 简化复制而来,避免误触原来的配置。
  • updatedList:当前拖拽产生的节点列表,也就是最新的节点列表。
  • addList:新节点的添加或旧节点版本更新时,就把对应节点添加到此数组中。
  • deleteList:在更新的列表中,原来的节点不见了,因为被删除了,找到这些被删除的节点,放进此数组中。
  1. 这个问题的关键在于要把不变的节点信息保留下来,因此不能直接用更新后的节点列表,因为如果直接用更新后的节点列表就会覆盖掉之前配置好的节点。
  2. 具体步骤是什么?(1) 利用 JSON.stringify() 方法整体上去对比新旧节点是否一样,如果一样,说明前后一致,没有进行任何操作,currentNodes 没有发生变化。(2) 如果不一样,说明节点发生变化。此时就要找出需要添加到 currentNodes 中的新的节点或需要从 currentNodes 中删除的旧的节点。
  • 遍历旧节点列表,找出当前旧节点在新节点列表中对应的相同 id 的节点,然后根据它们的版本 id 不同,进一步处理。如果版本 id 不同,把新版本的节点加入到 addList 中;再把原来的老版本的节点加入到 deleteList 中。
  • 如果在遍历后,没有找到相同 id 的节点,说明这个节点已经被删除了,于是把当前旧节点放进 deleteList 中。
  1. (3) 除了以上的情况,还有一种情况是:之前基于相同 id 来筛选,对于新的 id 的节点是选不出来的。例如,下图的 c、d 节点。

1688269148238.png


此时,遍历旧节点列表将旧节点id放进 oldNodeIdList 中,然后遍历新节点列表,找出不在 oldNodeIdList 中的节点,这些节点就是新增的节点,需要放进 addList 中。

三、算法

function differNodes (newNodes, oldNodes) {
  const addList = [] // 待添加的节点
  const deleteList = [] // 待删除的节点
  const oldNodeIdList = [] // 上一次节点 id 列表
  const isSame = JSON.stringify(oldNodes) === JSON.stringify(newNodes)
  if (!isSame) {
    oldNodes.forEach((oNode) => {
      const sameIdNode = newNodes.find((nNode) => nNode.nodeId === oNode.nodeId) // 筛选出id相同的节点
      if (sameIdNode) {
        if (sameIdNode.versionId !== oNode.versionId) {
          // 添加新节点
          addList.push(sameIdNode)
          // 删除老节点
          deleteList.push(oNode)
        }
      } else {
        // 没有在新的节点中找到和自己一样id的节点,说明自己被删了
        deleteList.push(oNode)
      }
    })
    // 新节点列表中未检测出的节点放进 addList
    oldNodes.forEach(oNode => {
      oldNodeIdList.push(oNode.nodeId)
    })
    newNodes.forEach((nNode) => {
      if (!oldNodeIdList.includes(nNode.nodeId)) {
        addList.push(nNode)
      }
    })
  }
  return {
    addList,
    deleteList
  }
}

四、参考代码

const { log } = console;
let currentNodes = [
  {nodeId: 'node_1', versionId: 'v1'},
  {nodeId: 'node_2', versionId: 'v1'},
  {nodeId: 'node_3', versionId: 'v1'}
];
log('更新前的currentNodes:', currentNodes);
const oldList = [
  {nodeId: 'node_1', versionId: 'v1'},
  {nodeId: 'node_2', versionId: 'v1'},
  {nodeId: 'node_3', versionId: 'v1'}
]
const updatedList = [
  {nodeId: 'node_4', versionId: 'v1'},
  {nodeId: 'node_5', versionId: 'v1'},
  {nodeId: 'node_6', versionId: 'v1'}
]
function differNodes (newNodes, oldNodes) {
  const addList = []
  const deleteList = []
  const oldNodeIdList = []
  const isSame = JSON.stringify(oldNodes) === JSON.stringify(newNodes)
  if (!isSame) {
    oldNodes.forEach((oNode) => {
      const sameIdNode = newNodes.find((nNode) => nNode.nodeId === oNode.nodeId)
      if (sameIdNode) {
        if (sameIdNode.versionId !== oNode.versionId) {
          addList.push(sameIdNode)
          deleteList.push(oNode)
        }
      } else {
        deleteList.push(oNode)
      }
    })
    oldNodes.forEach(oNode => {
      oldNodeIdList.push(oNode.nodeId)
    })
    newNodes.forEach((nNode) => {
      if (!oldNodeIdList.includes(nNode.nodeId)) {
        addList.push(nNode)
      }
    })
  }
  return {
    addList,
    deleteList
  }
}
const dealState = differNodes(updatedList, oldList);
const needAddList = dealState.addList;
const needDelList = dealState.deleteList;
needDelList.forEach(item => {
  const idx = currentNodes.findIndex(node => node.nodeId === item.nodeId);
  currentNodes.splice(idx, 1);
})
currentNodes.push(...needAddList)
log('更新前的currentNodes:', currentNodes);

CodePen 地址:codepen.io/knightdocs/…

添加我的微信:enjoy_Mr_cat,共同成长,卷卷群里等你 🤪。

以上,感谢您的阅读~

目录
相关文章
|
Java 定位技术 uml
每日一博 - 探索代码世界的地图 code iris
每日一博 - 探索代码世界的地图 code iris
541 0
R语言分布滞后线性和非线性模型DLM和DLNM建模应用| 系列文章
R语言分布滞后线性和非线性模型DLM和DLNM建模应用| 系列文章
|
敏捷开发 人工智能 安全
通义灵码+DeepSeek-R1:AI编程助手的新标杆?
通义灵码与DeepSeek-R1模型的深度集成,重新定义了AI编程工具的边界。该组合通过“大模型+垂直优化”技术路线,显著提升开发者效率。实测显示,在代码生成、上下文理解、缺陷检测等方面表现优异,函数补全响应时间仅0.8秒,内存占用减少41%,编码时间节省35%。适用于敏捷开发、系统重构等场景,尤其适合中小型研发团队和全栈开发者。
|
监控 Java Linux
大厂的OOM优化和监控方案(二)
大厂的OOM优化和监控方案(二)
大厂的OOM优化和监控方案(二)
|
数据采集 编解码 开发工具
Android平台实现无纸化同屏并推送RTMP或轻量级RTSP服务(毫秒级延迟)
一个好的无纸化同屏系统,需要考虑的有整体组网、分辨率、码率、实时延迟、音视频同步和连续性等各个指标,做容易,做好难
304 2
|
机器学习/深度学习 算法 大数据
云上智能风控:重塑金融风险管理的新篇章
随着金融科技的快速发展,监管机构对金融机构的监管要求也在不断提高。云上智能风控系统需要符合相关监管政策和法规的要求
|
小程序 物联网 定位技术
阿里云+微信小程序+GPS定位
阿里云物联网板块是一个功能非常强大的板块,而且通俗易懂,非常容易上手,比华为的要稍微容易上手一些。本次,小编通过阿里云物联网平台,将SIM800M32的GPS经纬度坐标发送到阿里云平台,并通过规则引擎转发数据至微信小程序,然后在地图上显示位置。
5329 0
|
人工智能 自然语言处理 语音技术
GigaSpeech 2:三万小时东南亚多语种语音识别开源数据集发布
GigaSpeech 2 是一个持续扩展的、多领域多语言的大规模语音识别语料库,旨在促进低资源语言语音识别领域的发展和研究。
|
Java 测试技术 Maven
JUnit5学习之五:标签(Tag)和自定义注解
学习和实践JUnit5的标签过滤和自定义注解功能
381 1
JUnit5学习之五:标签(Tag)和自定义注解
|
安全
多线程和异步编程:什么是线程安全?如何确保在多线程环境下的数据安全性?
多线程和异步编程:什么是线程安全?如何确保在多线程环境下的数据安全性?
1391 3