莫方教程网

专业程序员编程教程与实战案例分享

js树形数据根据子节点查找所有父节点,在前端侧边栏菜单实际应用

有如下的树形结构数据,一般前端侧边栏菜单中会经常用到这样的数据,现在需要通过某一层级的节点找出来包含自身的所有父节点:

const treeData = [
  {
    path: '/home',
    name: 'home',
    meta: {
      title: '首页',
    },
  },
  {
    path: '/tool',
    name: 'tool',
    children: [
      {
        path: '/tool/one',
        name: 'tool-one',
        meta: {
          title: '工具一',
        },
      },
      {
        path: '/tool/two',
        name: 'tool-two',
        meta: {
          title: '工具二',
        },
      },
      {
        path: '/tool/three',
        name: 'tool-three',
        meta: {
          title: '工具三',
        },
        children: [
          {
            path: '/tool/three/one',
            name: 'tool-three-one',
            meta: {
              title: '工具三-1',
            },
          },
          {
            path: '/tool/three/two',
            name: 'tool-three-two',
            meta: {
              title: '工具三-2',
            },
          },
        ],
      },
    ],
  },
  {
    path: '/system',
    name: 'system',
    meta: {
      title: '系统',
    },
    children: [
      {
        path: '/system/one',
        name: 'system-one',
        meta: {
          title: '系统一',
        },
        children: [
          {
            path: '/system/one/one',
            name: 'system-one-one',
            meta: {
              title: '系统一-1',
            },
          },
          {
            path: '/system/one/two',
            name: 'system-one-two',
            meta: {
              title: '系统一-2',
            },
          },
        ],
      },
      {
        path: '/system/two',
        name: 'system-two',
        meta: {
          title: '系统二',
        },
      },
    ],
  },
]

开始我的思路是用递归遍历,自己先定义一个空数组,每次循环最外层的时候先置空数组,把每一级的 name 都存到数组里,如果找到了目标元素就不用再修改数据,具体代码如下:

function findNames(menus, targetName = 'tool-three-two') {
  let isSuccess = false
  let names = []
  menus.map(m => {
    if (!isSuccess) {
      names = []
      getName(m, names, true)
    }
  })

  function getName(obj, arr) {
    if (isSuccess) return

    const name = obj.name
    arr.push(name)
    if (name === targetName) {
      isSuccess = true
    }

    const children = obj.children || []
    if (children.length) {
      children.map(c => {
        getName(c, arr, false)
      })
    }
  }

  return names
}

不过最后发现未过滤掉同级数据,相当于和目标值同级的所有 name 都被添加进去了,不过可以通过自己再过滤一遍数据来实现,方方有点笨,也能实现最后的效果。

终极版

最后在网上找到大神用的方法,兴高采烈地直接把人的 for 循环改成 map,死活没效果,开始还想是不是 for 和 map 有啥特殊区别,最后才反应过来 map 里的 return 并不是方法的返回值,所以一直没效。

function getNames(data, val) {
  for (let i = 0; i < data.length i if datai datai.name='== val)' return datai.name if datai datai.children let d='getNames(data[i].children,' val if d return d.concatdatai.name map return> {
  //   if (m && m.name === val) {
  //     return [m.name]
  //   }
  //   if (m && m.children && m.children.length) {
  //     let d = getNames(m.children, val)
  //     if (d) {
  //       return d.concat(m.name)
  //     }
  //   }
  // })
}

应用场景

树形结构一般在管理端项目的侧边栏菜单中用得比较多,刷新当前页面要求自动展开当前菜单,这也是很常见的一个需求。

iview 的菜单组件 Menu,当前选中菜单 active-name,一般直接用 this.$route.name 绑定,已展开的菜单 open-names,就需要动态来过滤出当前菜单的所有父级菜单,也就是需要用到上面的方法。注意要更新菜单的展开折叠状态需要自己在 nextTick 下调用方法 this.$refs.menu.updateOpened(),否则刷新或者首次进入时,菜单不会自动展开。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言