JS树状结构处理(新增、删除、查找)

在遇到如下类型的树状结构列表时,在新增、修改、删除的时候需要即时更新列表。

 数据结构一览:

data = [
    {
        "id": 1,
        "pid": 0,
        "font_route": "",
        "api_action": "",
        "is_menu": 1,
        "is_show": 0,
        "title": "数据统计",
        "children": [
            {
                "id": 2,
                "pid": 1,
                "font_route": "/main/ActivityList",
                "api_action": "Index/getActivityList",
                "is_menu": 1,
                "is_show": 1,
                "title": "文章列表",
                "children": [
                    {
                        "id": 6,
                        "pid": 2,
                        "font_route": "/main/ArticleHot",
                        "api_action": "Index/getArticleHot",
                        "is_menu": 0,
                        "is_show": 1,
                        "title": "文章热度统计"
                    }
                ]
            }
        ]
    }
    
 ]

那么有以下几种方案可以实现:

  1. 刷新页面
  2. 再次向服务器发起请求,更新数据
  3. 直接更改此次列表数据,vue中会自动刷新视图

 第一、第二种方案都需要再次发送请求与服务端交互,比较浪费带宽与效率。这里重点说下第三种直接修改本次列表数据的方法。

直接修改树状结构的话,常用的方法就是递归操作,通过递归实现树状结构的新增、删除、查找。

新增对象

直接上基础代码:【以id作为关键词,children作为下级字段】

const handleData = (id, data, obj) => {
  data.forEach(item => {
    if (item.id === id) {
      item.children ? item.children.push(obj) : item.children = [obj]
    } else {
      if (item.children) {
        handleData(id, item.children, obj)
      }
    }
  })
  return data
}

改写可以自定义关键词、自定义下级字段的函数:

function insertTreeListItem (treeList, key , item , childField ,keyField) {

    var childField = arguments[3] ? arguments[3] : 'children'
    var keyField = arguments[4] ? arguments[4] : 'id'

    treeList.forEach(treeitem => {
      if (treeitem[keyField] === key) {
        treeitem[childField] ? treeitem[childField].push(item) : treeitem[childField] = [item]
      } else {
        if (treeitem[childField]) {
            insertTreeListItem(treeitem[childField], key , item , childField ,keyField)
        }
      }
    })
    return treeList
}

使用vue的请注意:

在vue中如果直接使用以上代码修改原数据的话,那么你会发现数据虽然更新了,但是有时候视图并没有更新。细心的小伙伴应该很快发现了,其中有对象的直接赋值语句。

总所周知,在vue2中直接的对象赋值时无法更新视图的。在本案例中由于是公共函数,也不可能在函数中直接使用this.$set赋值。解决方案有两个:

1、让后台为每一个item都加上children的子项目,这样前端就不用使用对象赋值了。
2、前端不直接传入data的值,通过深拷贝得到一个数据,再重新赋值回data

这里推荐使用第二种方法:

 删除对象

删除对象写起来比较简单,本质上也是递归。删除可以不用返回新数据,直接影响原数组也问题不打,需要返回新对象的可以直接改写一下。

基础函数:

function removeTreeListItem(treeList, id) { // 根据id属性从数组(树结构)中移除元素
  if (!treeList || !treeList.length) {
    return
  }
  for (let i = 0; i < treeList.length; i++) {
    if (treeList[i].id === id) {
      treeList.splice(i, 1);
      break;
    }
    removeTreeListItem(treeList[i].children, id)
  }
}

改写成可以自定义关键词、自定义下级字段的函数

function removeTreeListItem(treeList, key , childField ,keyField) { 

    var childField = arguments[2] ? arguments[2] : 'children'
    var keyField = arguments[3] ? arguments[3] : 'id'

    if (!treeList || !treeList.length) {
      return
    }
    for (let i = 0; i < treeList.length; i++) {
      if (treeList[i][keyField] === key) {
        treeList.splice(i, 1);
        break;
      }
      removeTreeListItem(treeList[i][childField], key ,childField ,keyField)
    }
}

查找对象

基础函数:

getObjByTree = (data, id) => {
        let result = null
        if (!data) return // return; 中断执行
        for (let i in data) {
            if (result !== null) break
            let item = data[i];
            if (item.id=== id) {
                result = item;
                break;
            } else if (!!item?.children?.length) {
                result = this.getObjByTree(item.children, id);
            }
        }
        return result;
    }

改写成可以自定义关键词、自定义下级字段的函数

function searchTree(treeList, key , childField ,keyField){

    var childField = arguments[2] ? arguments[2] : 'children'
    var keyField = arguments[3] ? arguments[3] : 'id'

    let result = null
    if (!treeList) return // return; 中断执行
    for (let i in treeList) {
        if (result !== null) break
        let item = treeList[i];
        if (item[keyField]=== key) {
            result = item;
            break;
        } else if ( item[childField] && item[childField].length>0 ) {
            result = searchTree(item[childField], key);
        }
    }
    return result;
}

以上三个函数,应该可以解决大部分的树状结构数据相关的业务代码

关于树状结构数据的更多操作,这里推荐一篇文章:JS树结构操作:查找、遍历、筛选、树结构和列表结构相互转换 - 沐码小站

  • 8
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值