theme: jzman

highlight: atelier-cave-light

一、前言

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

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

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

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

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

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

  1. 节点的结构如下:

js const node = { nodeId: 'node_1', versionId: 'v1' }

  1. 节点列表的结构如下:

js 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:在更新的列表中,原来的节点不见了,因为被删除了,找到这些被删除的节点,放进此数组中。

    这个问题的关键在于要把不变的节点信息保留下来,因此不能直接用更新后的节点列表,因为如果直接用更新后的节点列表就会覆盖掉之前配置好的节点。

  2. 具体步骤是什么?

    (1) 利用 JSON.stringify() 方法整体上去对比新旧节点是否一样,如果一样,说明前后一致,没有进行任何操作,currentNodes 没有发生变化。

    (2) 如果不一样,说明节点发生变化。此时就要找出需要添加到 currentNodes 中的新的节点或需要从 currentNodes 中删除的旧的节点。

    • 遍历旧节点列表,找出当前旧节点在新节点列表中对应的相同 id 的节点,然后根据它们的版本 id 不同,进一步处理。如果版本 id 不同,把新版本的节点加入到 addList 中;再把原来的老版本的节点加入到 deleteList 中。

    • 如果在遍历后,没有找到相同 id 的节点,说明这个节点已经被删除了,于是把当前旧节点放进 deleteList 中。

    (3) 除了以上的情况,还有一种情况是:之前基于相同 id 来筛选,对于新的 id 的节点是选不出来的。例如,下图的 c、d 节点。

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

三、算法

js 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 } }

四、参考代码

```js const { log } = console;

let currentNodes = [ {nodeId: 'node1', versionId: 'v1'}, {nodeId: 'node2', versionId: 'v1'}, {nodeId: 'node_3', versionId: 'v1'} ]; log('更新前的currentNodes:', currentNodes);

const oldList = [ {nodeId: 'node1', versionId: 'v1'}, {nodeId: 'node2', versionId: 'v1'}, {nodeId: 'node3', versionId: 'v1'} ] const updatedList = [ {nodeId: 'node4', versionId: 'v1'}, {nodeId: 'node5', versionId: 'v1'}, {nodeId: 'node6', 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 地址:https://codepen.io/knightdocs/pen/WNOwwgj?editors=0011

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

新旧节点对比与更新:differNodes相关推荐

  1. Java核心技术:日期和时间新旧API对比

    本文作者:小虚竹,CSDN博客专家&CSDN原力计划作者,Java领域优质创作者,掘金年度人气作者,华为云专家,阿里云专家博主,51CTO专家博主.是一个乐于分享"IT圈" ...

  2. 一建机电实务教材电子版_2020一建教材+章节习题+新旧教材对比【全科】免费送...

    2020一建<各科>电子教材 2020一建<工程法规>电子教材 2020一建<工程经济>电子教材 2020一建<公路实务>电子教材 2020一建< ...

  3. ffmpeg新旧接口对比--记录

    https://www.cnblogs.com/schips/p/12197116.html ffmpeg新旧函数对比_鲲鹏私董会的博客-CSDN博客 ffmpeg 视频解码流程及对应API使用_ff ...

  4. 历史的变迁:北京新旧地铁站对比

    今天(2019年4月25日)到航天一院和航天二院去进行技术交流,这两个研究院分别隶属中国航天科技集团和科工集团,算是国内顶级的研究机构. 这两个研究院地理位置都处于北京的黄金区域,一院在四环和五环中间 ...

  5. 2023一建各科教材新旧变化对比

    一建新教材都已经出来了,真的没有理由再拖着不复习了.一建各科新教材改动比例也随之出来了.其中经济5%.市政5%.水利7%.建筑7%.法规8%.管理10%.公路10%.机电12%.最高的是铁路17%,从 ...

  6. Untiy InputSystem(一) 新旧API对比

    前言 新的输入系统在跨平台方面便捷了不少,最近公司在弄工具,其中一个功能就是希望实现PC和VR及其他平台的快速切换,输入模块正好用的上,先简单梳理下,后面有空再仔细研究. 一.前置操作 1.官方文档 ...

  7. 详解java中的日期与时间;新旧API对比;各种日期格式转换

    一.基本概念 1.本地时间 不同的时区,在同一时刻,本地时间是不同的. 全球一共分为24个时区,伦敦所在的时区称为标准时区,其他时区按东/西偏移的小时区分,北京所在的时区是东八区. 2.时区 GMT ...

  8. React生命周期(包含新旧流程图对比)

    React生命周期 文章目录 React生命周期 对于生命周期的理解 重要的生命周期勾子 废弃的勾子 生命周期流程图(旧) 生命周期流程图(新) React 16.8以后的生命周期分为三个阶段,分别是 ...

  9. ffmpeg新旧函数对比

    从FFmpeg 3.0 开始 , 使用了很多新接口,对不如下: 1. avcodec_decode_video2() 原本的解码函数被拆解为两个函数avcodec_send_packet()和avco ...

最新文章

  1. Hibernate5-双向关联-多对多(n:n)
  2. 24个很赞的 Node.js 免费教程和在线指南
  3. DOS命令温习(图解)
  4. java前补零工具类_java生成编码工具类,不足补0
  5. React开发(103):详细路径 不然找不到
  6. java获取正在执行的timer_Java线程与并行编程(一)
  7. Hive与Hbase数据表关联
  8. 百位云计算专家齐聚湖畔大学,阿里云MVP全球闭门会聚焦数字化转型
  9. upload组件 获得焦点_HTML Input FileUpload autofocus用法及代码示例
  10. 悟道魔兽世界,《榜样魔兽》横空出世
  11. K8S 的报错问题解决
  12. LDA(线性判别分析或称Fisher线性判别),PCA(主成份分析)代码及表情识别中的应用
  13. mysql checking permissions 优化_mysql 查询优化 ~ 善用profie利器
  14. 3.29 段落文字的属性设置 [原创Ps教程]
  15. python 拼接 遥感影像_Python干货 | 遥感影像拼接
  16. sudo报错及在linux上启动jar包时报错java.net.UnknownHostException
  17. 鸿蒙OS到底是不是Android套皮?(少bb,看源码!)
  18. Ubuntu 平台的防火墙关闭命令
  19. 接口的方式获取bing必应每天壁纸
  20. p站自动收藏画作 post请求,request payload

热门文章

  1. 传闻中能取代90%人工作的chatGPT,不值得让软测人恐慌
  2. 初识C语言 —— 数组(一)
  3. leetcode554、砖墙
  4. 修改xfs的inode方法
  5. 2017年鸡年春联节选
  6. 利用Python爬取github上commits信息
  7. u盘拷贝显示目标文件过大怎么办-解决方法
  8. python try catch 所有异常_python错误处理—try…catch…finally、调用栈分析
  9. android 代码打开usb调试,Android手机USB调试在哪?安卓手机如何打开USB调试模式?...
  10. 搭建http2 mTLS通道,实现本地/远程端口转发(gost)