递归的用法 权限列表新增移除恢复

77 阅读6分钟

何为递归

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己, 这个函数就是递归函数

注意:  递归函数的作用和循环效果一样,由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件return。

递归在实际中的作用

 递归扁平化数据 转成tree结构
 递归深拷贝
 递归求和
 递归做数据的增删改查

递归深拷贝

// 深度克隆  
const deepClone = (value) => {  
  // 判断是数组 递归复制出去  
  if (Array.isArray(value)) {  
    const clone = []  
    for (let i = 0; i < value.length; i++) {  
      clone[i] = deepClone(value[i]);  
    }  
    return clone  
  }  
  // 如果是对象同理  
  if (typeof value === 'object' && typeof value !== null) {  
    const obj = {}  
    for (var key in obj) {  
      obj[key] = deepClone(value[key])  
    }  
    return obj  
  }  
  // 原值直接返回  
  return value  
}

递归求和

function sum (nums) {  
  function getArr (param) {  
    return param >= nums.length ? 0 : nums[param] + getArr(param + 1)  
  }  
  return getArr(0)  
}

接着就讲讲 今天用到的地方

  • 页面的功能是这样的

机构端软著.png

  • 需求是点击移除要移除数据 数据移除后按钮显示恢复 点击恢复又要恢复对应的数据
  • 这里其实功能可以用显示隐藏来做 但是由于我用了树形结构 懒得写页面了 所以没有这样做
页面结构
<el-tree :data="data.nodeMenuList" :props="defaultProps" node-key="id" show-checkbox :default-expanded-keys="[1]" @check="checkPermission">  
          <template #default="{ node, data }">  
            <div class="custom-tree-node">  
              <span>{{ node.label }} {{ data.children.length }}</span>  
              <span class="icons-box" v-if="node.label != 'admin'">  
                <span class="icons-box" @click.stop="handleBtn(data, 'delete')" v-if="data.children.length > 0">  
                  <el-icon size="18">  
                    <icons.Minus />  
                  </el-icon>  
                </span>  
                <span class="icons-box" @click.stop="handleBtn(data, 'add')" v-else>  
                  <el-icon size="18">  
                    <icons.Plus />  
                  </el-icon>  
                </span>  
              </span>  
            </div>  
          </template>  
        </el-tree>
删除逻辑
拿到点击的数据 查找id是否存在 存在添加到删除数组;  
不存在表示当前节点不是需要删除的节点, 即递归调用自身,继续对当前节点的子节点进行遍历;  
这是为了深度遍历整个树结构,找到所有需要删除的节点。
  • 恢复节点的逻辑稍微复杂一点点
 首先要拿到恢复节点的id  
 其次 要有个选定节点的数组matchingNodes 目的是用来匹配被删除的数组 保存需要恢复的节点  
 跟删除一样 递归查找id存在吗  
 恢复节点 同是要删除对应删除数组里面的数据
代码 逐行解释

const deleteNodeAndChildren = (parentNode: any, nodeId: any, deletedNodes: any) => {  
  if (!parentNode.children || parentNode.children.length === 0return 
  parentNode.children = parentNode.children.filter((childNode: any) => {  
    if (childNode.fid === nodeId) {   // 查找id 如果父级id相同那么是用一个数据 就添加到删除数组
      data.deletedNodes.push(childNode)  
      return  
    }  
    deleteNodeAndChildren(childNode, nodeId, deletedNodes)  // 递归调用数据 查找所有的数据
    return  
  })  
}  
  
// 删除节点  
const handleDeleteNode = (nodeData: any) => {  
  deleteNodeAndChildren(nodeData, nodeData.id, data.deletedNodes)  
}  
// 恢复节点 node:点击的每个子节点数据  
const handleRestoreNodes = () => {  
    // selectedNodeToRestore这是点击恢复的id
  if (selectedNodeToRestore.value !== null) {  
    // 递归查找所有匹配的节点  
    const findMatchingNodes = (nodes: any, fid: any, result: any) => {  
      for (const node of nodes) {  
        if (node.fid === fid) {  // 同理也是拿到id比对
          result.push(node)  
        }  
        if (node.children && node.children.length > 0) {  // 这句可加可不加
          findMatchingNodes(node.children, fid, result)  
        }  
      }  
    }  
    const matchingNodes = [] as any  
    findMatchingNodes(data.deletedNodes, selectedNodeToRestore.value, matchingNodes)  
    if (matchingNodes.length > 0) {  
      // 恢复所有匹配的节点  
      for (const selectedNode of matchingNodes) {  
        handleAddNode(selectedNode)  
      }  
      selectedNodeToRestore.value = null // 恢复后删除节点  
    }  
  }  
}  
  
// 恢复节点操作 nodeID:点击的id parentNode:里面的每一条数据  
const handleAddNode = (parentNode: any) => {  
  const nodeId = parentNode.fid // 点击的id  
  const findAndAddNode = (items: any[], parentId: number) => {  
    for (const item of items) {  
      if (item.id === parentId) {  
        item.children.push(parentNode)  
        // 从deletedNodes中删除对应的节点  
        data.deletedNodes = data.deletedNodes.filter((node: any) => node.id !== parentNode.id)  
        return true // 添加节点退出递归  
      }  
      if (item.children && findAndAddNode(item.children, parentId)) {  
        return true  
      }  
    }  
    return false // 没有节点  
  }  
  // 恢复节点  
  findAndAddNode(data.nodeMenuList, nodeId)  
}  
const handleBtn = (data: any, type: string) => {  
  console.log(data, type)  
  if (type === 'delete') {  
    handleDeleteNode(data)  
  } else if (type === 'add') {  
    selectedNodeToRestore.value = data.id  
    handleRestoreNodes()  
  }  
}
数据格式
arr:[
0:{
 children:[
    {
    "id": 2,
    "name": "admin",
    "title": "权限设置",
    "fid": 1,
    "type": 1,
    "status": 1,
    "sort": 1,
    "condition": "",
    "create_time": "2018-07-11 18:24:04",
    "update_time": "2019-06-18 11:53:38",
    "children": [
        {
            "id": 3,
            "name": "admin/1",
            "title": "管理权限",
            "fid": 2,
            "type": 1,
            "status": 1,
            "sort": 0,
            "condition": "",
            "create_time": "2018-07-11 18:24:04",
            "update_time": "2019-06-18 11:56:00",
            "children": [
                {
                    "id": 4,
                    "name": "admin/group",
                    "title": "权限组列表",
                    "fid": 3,
                    "type": 1,
                    "status": 1,
                    "sort": 10,
                    "condition": "",
                    "create_time": "2018-07-11 18:24:04",
                    "update_time": "2019-06-18 15:13:44",
                    "children": [
                        {
                            "id": 10,
                            "name": "admin/groupadd",
                            "title": "增加",
                            "fid": 4,
                            "type": 1,
                            "status": 1,
                            "sort": 3,
                            "condition": "",
                            "create_time": "2018-07-13 10:46:23",
                            "update_time": "2019-06-18 15:13:57",
                            "children": []
                        },
                        {
                            "id": 11,
                            "name": "admin/groupedit",
                            "title": "修改",
                            "fid": 4,
                            "type": 1,
                            "status": 1,
                            "sort": 2,
                            "condition": "",
                            "create_time": "2018-07-13 10:46:52",
                            "update_time": "2019-06-18 15:14:05",
                            "children": []
                        },
                        {
                            "id": 12,
                            "name": "admin/groupdel",
                            "title": "删除",
                            "fid": 4,
                            "type": 1,
                            "status": 1,
                            "sort": 1,
                            "condition": "",
                            "create_time": "2018-07-13 10:47:24",
                            "update_time": "2019-06-18 15:14:12",
                            "children": []
                        }
                    ]
                },
                {
                    "id": 8,
                    "name": "admin/index",
                    "title": "管理员列表",
                    "fid": 3,
                    "type": 1,
                    "status": 1,
                    "sort": 9,
                    "condition": "",
                    "create_time": "2018-07-11 19:40:04",
                    "update_time": "2019-06-18 15:16:12",
                    "children": [
                        {
                            "id": 9,
                            "name": "admin/manageradd",
                            "title": "添加",
                            "fid": 8,
                            "type": 1,
                            "status": 1,
                            "sort": 3,
                            "condition": "",
                            "create_time": "2018-07-12 19:15:55",
                            "update_time": "2019-06-18 15:16:25",
                            "children": []
                        },
                        {
                            "id": 13,
                            "name": "admin/manageredit",
                            "title": "修改",
                            "fid": 8,
                            "type": 1,
                            "status": 1,
                            "sort": 2,
                            "condition": "",
                            "create_time": "2018-07-13 10:49:05",
                            "update_time": "2019-06-18 15:16:33",
                            "children": []
                        },
                        {
                            "id": 14,
                            "name": "admin/managerdel",
                            "title": "删除",
                            "fid": 8,
                            "type": 1,
                            "status": 1,
                            "sort": 1,
                            "condition": "",
                            "create_time": "2018-07-13 10:49:28",
                            "update_time": "2019-06-18 15:16:40",
                            "children": []
                        }
                    ]
                },
                {
                    "id": 15,
                    "name": "admin/logg",
                    "title": "后台操作日志",
                    "fid": 3,
                    "type": 1,
                    "status": 1,
                    "sort": 7,
                    "condition": "",
                    "create_time": "2018-07-13 10:50:43",
                    "update_time": "2019-06-18 15:16:49",
                    "children": [
                        {
                            "id": 16,
                            "name": "admin/loggdel",
                            "title": "删除",
                            "fid": 15,
                            "type": 1,
                            "status": 1,
                            "sort": 1,
                            "condition": "",
                            "create_time": "2018-07-13 10:51:19",
                            "update_time": "2019-06-18 15:16:56",
                            "children": []
                        },
                        {
                            "id": 18,
                            "name": "admin/loggdelall",
                            "title": "清空",
                            "fid": 15,
                            "type": 1,
                            "status": 1,
                            "sort": 0,
                            "condition": "",
                            "create_time": "2018-07-14 15:31:54",
                            "update_time": "2019-06-18 15:17:03",
                            "children": []
                        }
                    ]
                },
                {
                    "id": 5,
                    "name": "admin/node",
                    "title": "节点管理(管理员)no",
                    "fid": 3,
                    "type": 1,
                    "status": 1,
                    "sort": 0,
                    "condition": "",
                    "create_time": "2018-07-11 18:24:04",
                    "update_time": "2018-07-20 10:40:03",
                    "children": [
                        {
                            "id": 7,
                            "name": "admin/nodeadd",
                            "title": "添加",
                            "fid": 5,
                            "type": 1,
                            "status": 1,
                            "sort": 3,
                            "condition": "",
                            "create_time": "2018-07-11 18:14:41",
                            "update_time": "2019-06-18 15:19:37",
                            "children": []
                        },
                        {
                            "id": 6,
                            "name": "admin/nodeedit",
                            "title": "修改",
                            "fid": 5,
                            "type": 1,
                            "status": 1,
                            "sort": 2,
                            "condition": "",
                            "create_time": "2018-07-11 15:03:54",
                            "update_time": "2019-06-18 15:19:43",
                            "children": []
                        },
                        {
                            "id": 17,
                            "name": "admin/nodedel",
                            "title": "删除",
                            "fid": 5,
                            "type": 1,
                            "status": 0,
                            "sort": 1,
                            "condition": "",
                            "create_time": "2018-07-13 10:52:37",
                            "update_time": "2019-06-18 15:19:51",
                            "children": []
                        }
                    ]
                }
            ]
        }
    ]
}
 ]
 condition: ""
 create_time: "2018-07-11 18:03:36"
 fid: 0
 id: 1
 name: "root"
 sort: 100
 status: 1
 title: "admin"
 type: 1
 update_time: "2023-12-08 17:23:53"
}
]

结尾

如果有遇到同样功能的小伙伴想要用递归来做的可以使用这段代码 同时也欢迎各位大佬指点 这里还有一个不完善的地方 例如我们删除全局下的某一个节点 然后再把全局节点删除 接着恢复全局节点 这时候被删除的节点数据没有恢复需要我们手动去恢复 这个问题有大佬能解答吗