zoukankan      html  css  js  c++  java
  • 动态树形菜单的几种递归写法小结

    vue递归方法实现:

    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>

    方法二:

    APP.vue

    <template>
      <div id="app">
        <Home :items="items"></Home>
      </div>
    </template>
    
    <script>
    import Home from "./components/Home.vue";
    
    export default {
      name: "App",
      data() {
        return {
          items: [
            {
              name: "IT互联网",
              child: [
                {
                  name: "编辑语言",
                  child: [
                    { name: "java" },
                    { name: "c#/ .net" },
                    { name: "python" },
                  ],
                },
                {
                  name: "前端开发",
                  child: [{ name: "jq" }, { name: "vue " }, { name: "react " }],
                },
                {
                  name: "移动开发",
                  child: [{ name: " android开发" }, { name: "IOS开发" }],
                },
                {
                  name: "游戏开发",
                  child: [
                    { name: " phaser游戏开发" },
                    { name: "webGL游戏开发", child: [{ name: "3D游戏" }] },
                  ],
                },
              ],
            },
          ],
        };
      },
      components: {
        Home,
      },
    };
    </script>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>

    Home.vue

    <template>
      <div class="lists">
        <Item v-for="(v, i) in items" :key="i" :item="v"></Item>
      </div>
    </template>
    
    <script>
    import Item from "./Item";
    export default {
      name: "",
      components: { Item },
      data() {
        return {};
      },
      props: ["items"],
    };
    </script>
    
    <style></style>

    Item.vue

    <template>
      <ul>
        <li>
          <div>{{ item.name }}</div>
          <Item v-for="(v, i) in item.child" :key="i" :item="v"></Item>
        </li>
      </ul>
    </template>
    
    <script>
    export default {
      name: "Item",
      components: {},
      data() {
        return {};
      },
      props: ["item"],
    };
    </script>
    
    <style></style>

    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  实现无极限目录树完整版

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            div {
                margin-left: 20px;
                cursor: pointer;
            }
            .has-child {
                position: relative;
            }
            .has-child::before {
                content: '+';
                position: absolute;
                left: -20px;
            }
            .has-child > div {
                display: none;
            }
            .has-child.expend > div {
                display: block;
            }
            .has-child.expend::before {
                content: '-';
            }
        </style>
    </head>
    <body>
        <div id="demo"></div>
        <script>
            var data = [{
                name: '一级标题1',
                children: [{
                    name: '二级标题1',
                    children: [{
                        name: '三级标题'
                    }]
                }, {
                    name: '二级标题2',
                    children: [{
                        name: '三级标题'
                    }]
                }]
            }, {
                name: '一级标题2',
                children: [{
                    name: '二级标题1',
                    children: [{
                        name: '三级标题',
                        children: {
                            name: '四级标题'
                        }
                    }]
                }]
            }, {
                name: '一级标题3',
                children: [{
                    name: '二级标题1',
                    children: [{
                        name: '三级标题'
                    }]
                }, {
                    name: '二级标题2',
                    children: [{
                        name: '三级标题'
                    }]
                }, {
                    name: '二级标题3'
                }]
            }]
            
            // 用来创建目录树结构的函数
            /**
            * data 目录树的数据
            * parentNode:   将目录树结构插入到哪个节点下
            */
            function dTree(data, parentNode) {
                // 做一个兼容  如果当前没有传递父节点则创建一个父节点
                if (!parentNode) {
                    parentNode = document.createElement('div');
                    parentNode.className = 'root';
                }
                // 遍历数据中的每一项创建目录树的结构
                data.forEach(function (item) {
                    var node = document.createElement('div');
                    node.innerText = item.name;
                    // 阻止事件冒泡
                    node.onclick = function (e) {
                        e.stopPropagation();
                    }
                    // 判断当前标题下面是否含有子标题如果含有的话继续创建标题结构
                    if(item.children && item.children.length > 0) {
                        // 如果含有子标题则添加一个has-child的类名
                        node.className = 'has-child';
                        // 如果含有子标题则当前的标题可以点击展开
                        node.onclick = function (e) {
                            e.stopPropagation();
                            if (this.classList.contains('expend')) {
                                this.classList.remove('expend')
                            } else {
                                this.classList.add('expend')
                            }
                            
                        }
                        // 如果有子标题的话 需要继续创建子标题的结构
                        dTree(item.children, node);
                    }
                    parentNode.appendChild(node);
                })
                // 当前函数直接返回创建出来的目录树结构  由于所有的结构都插入到了父节点当中,因此可以返回父节点
                return parentNode
            }
    
            var demo = document.getElementById('demo');
    
            dTree(data, demo);
    
        </script>
    </body>
    </html>

    ...

  • 相关阅读:
    docker命令总结
    VulToEs
    MYSQL
    MoonStack
    Spring mvc json null
    MySQL
    极光推送
    坑爹的RockSaw和坑爹的windows7
    App接口设计思路
    CSUOJ 1329 一行盒子(数组模拟链表)
  • 原文地址:https://www.cnblogs.com/wxyblog/p/11618686.html
Copyright © 2011-2022 走看看