动态树形菜单的几种递归写法小结

Posted wxyblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态树形菜单的几种递归写法小结相关的知识,希望对你有一定的参考价值。

VUE中递归算法实现树形菜单的写法:

<template>
    <div>
        <!-- 父组件将数据传入子组件 -->
        <tree :msg=‘msg‘ />
    </div>
</template>

<script>

export default   
    data ()  //模拟数据
        return
            n:0,
            msg: [name:‘北京‘,
                    sub:[name:‘东城区‘,
                    sub:[
                        name:‘朝阳区‘
                    ]                 
                    ,name:‘西城区‘,
                        sub:[
                            name:‘关虎屯‘
                        ]
                    
                    ,name:‘南城区‘,name:‘北城区‘]
                    
                    ,
                    name:‘广东‘,
                    sub:[name:‘广州‘,
                        sub:[name:‘越秀区‘,name:‘白云区‘,name:‘海珠区‘]
                        ,
                        name:‘深圳‘,
                        sub:[name:‘蛇口区‘,name:‘保安区‘,name:‘盐田区‘]
                        ,
                    ]
                    ,
                    name:‘湖北‘,
                    sub:[name:‘武汉‘,
                        sub:[name:‘江夏区‘,name:"洪山区",name:‘江汉区‘]
                        ,
                        name:‘天门市‘,
                        sub:[name:‘精灵‘,name:"小班",name:‘打扮‘]
                        ]
                    ],
        
    ,
    // 注册父组件
    components: 
        tree:
            name:‘gs‘,//递归的构造函数名

            //父组件模板,相当于构造函数return的值
            template:`
            <ul>
                <li v-for="(v,i) in msg" :key=i @click.stop.self=‘n=i‘>  //第一层的数据,点击之后,子集菜单会展开,其他子集菜单会关闭
                     v.name 
                     
                     <gs :msg=v.sub  v-if="i==n"/>//将下一层数据传入构造函数,进行调用,形成递归,相当于自己调用自己,这一步是最关键的一步,
                </li>
            </ul> 
            `,
            props: [‘msg‘],//接受父组件传的值
            data()
                return
                    n:0  //默认展开的菜单下标
                
            
        ,
    

</script>

 

JS递归方法实现:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button onclick="fun()">递归测试</button>
    <div id="div">

    </div>

    <script>
        //模拟数据
        var data = [
            name: 1,
            sub: [
                name: ‘1-1‘,
                sub: []
            ]
        , 
            name: 2,
            sub: [
                    name: "2-1",
                    sub: [
                            name: ‘2-1-1‘,
                            sub: []
                        , 
                            name: ‘2-1-2‘,
                            sub: []
                        

                    ]
                , 
                    name: "2-2",
                    sub: [
                        name: ‘2-2-1‘,
                        sub: []
                    , 
                        name: ‘2-2-2‘,
                        sub: [
                            name: ‘2-2-2-1‘,
                            sub: []
                        ]
                    ]
                

            ]
        , 
            name: 3,
            sub: []
        ]


        var div = document.getElementById(‘div‘)
        var str = ‘‘;

      //递归函数
function list(data) if (data) if (data.length > 0) str += "<ul>"; for (let v = 0; v < data.length; v++) const item = data[v]; str += ‘<li>‘ + item.name; list(item.sub) str += ‘</li>‘; str += "</ul>"; list(data) console.log(str) div.innerHTML = str;


//以下是递归测试函数,与树形菜单无关
var arr = []; function fun() var num = parseFloat(prompt("输入数字:")); if (typeof(num) == ‘number‘) while (num > 0) arr.push(num) num--; //console.log(arr) var arrlist = []; // var data=[1,[2,3],[4,[5,6,[8]]],9,[10]]; var fun3 = arr => [...arr].map((item) => Array.isArray(item) ? fun3(item) : arrlist.push(item)); fun3(data) // console.log( fun3(data)) </script> </body> </html>

 

使用VUE + element-ui   实现树形菜单:

<template>
  <div class="custom-tree-container">
    <div class="block">
      <p>使用 render-content</p>
      <el-tree
        :data="data"
        show-checkbox
        node-key="id"
        default-expand-all
        :expand-on-click-node="false"
        :render-content="renderContent"
      ></el-tree>
    </div>
    <div class="block">
      <p>使用 scoped slot</p>
      <el-tree
        :data="data"
        show-checkbox
        node-key="id"
        default-expand-all
        :expand-on-click-node="false"
      >
        <span class="custom-tree-node" slot-scope=" node, data ">
          <span> node.label </span>
          <span>
            <el-button type="text" size="mini" @click="() => append(data)">Append</el-button>
            <el-button type="text" size="mini" @click="() => remove(node, data)">Delete</el-button>
          </span>
        </span>
      </el-tree>
    </div>

    <button @click="getAdd">+</button>
    <button @click="getjian">-</button>
  </div>
</template>
<script>
let id = 1000;

export default 
  data() 
    const data = [
      
        name: "北京",
        sub: [
          
            name: "北京",
            sub: [
               name: "东城区" ,
               name: "西城区" ,
               name: "南城区" ,
               name: "北城区" 
            ]
          
        ]
      ,
      
        name: "广东",
        sub: [
          
            name: "广州",
            sub: [ name: "越秀区" ,  name: "白云区" ,  name: "海珠区" ]
          ,
          
            name: "深圳",
            sub: [ name: "蛇口区" ,  name: "保安区" ,  name: "盐田区" ]
          
        ]
      ,
      
        name: "湖北",
        sub: [
          
            name: "武汉",
            sub: [ name: "江夏区" ,  name: "洪山区" ,  name: "江汉区" ]
          ,
          
            name: "天门市",
            sub: [ name: "精灵" ,  name: "小班" ,  name: "打扮" ]
          
        ]
      
    ];
   //关键部分
    let _data = function(data) 
      return data.map(v => 
        if (v.sub)         // 遍历数据,将菜单数据赋值给 ui框架指定属性名
          v.label = v.name;
          v.children = v.sub;
          return _data(v.sub);
        
        if (v.name && !v.sub) 
          v.label = v.name;
          return 123;
        
      );
    ;
    _data(data);
    return 
      data: JSON.parse(JSON.stringify(data)),  //将处理过的数据进行深刻隆
      data: JSON.parse(JSON.stringify(data))
    ;
  ,

  methods: 
    append(data) 
      const newChild =  id: id++, label: "testtest", children: [] ;
      if (!data.children) 
        this.$set(data, "children", []);
      
      data.children.push(newChild);
    ,

    remove(node, data) 
      const parent = node.parent;
      const children = parent.data.children || parent.data;
      const index = children.findIndex(d => d.id === data.id);
      children.splice(index, 1);
    ,

    renderContent(h,  node, data, store ) 
      return (
        <span class="custom-tree-node">
          <span>node.label</span>
          <span>
            <el-button
              size="mini"
              type="text"
              on-click=() => this.append(data)
            >
              Append
            </el-button>
            <el-button
              size="mini"
              type="text"
              on-click=() => this.remove(node, data)
            >
              Delete
            </el-button>
          </span>
        </span>
      );
    ,
    getAdd() 
      this.$store.commit("increment");
      console.log("我是加法" + this.$store.state.count);
    ,
    getjian() 
      this.$store.commit("jian", 2);
      console.log("我是加Z法" + this.$store.state.count);
    
  ,
  mounted() 
    console.log(this.$store.state.count);
  
;
</script>

<style>
.custom-tree-node 
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;

</style>

 

以上是关于动态树形菜单的几种递归写法小结的主要内容,如果未能解决你的问题,请参考以下文章

js通过数据动态渲染无级树形菜单

iOS 动态树形结构 - 实现多级菜单,附带复选框功能

JavaScript 递归的几种写法

Vue.js怎样把递归组件构建为树形菜单

MenuTreeUtil菜单树形递归工具类

vue递归组件—开发树形组件Tree--(构建树形菜单)