vue 递归组件

作者: Fate0 | 来源:发表于2018-01-09 21:34 被阅读0次

    vue 递归组件

    前言

    对于一些有规律的 dom 结构,我们可以通过递归方式来生成这个结构,,那么在 vue 的模板中,我们能不能递归生成dom,答案是肯定的,在 vue 的组件中能够调用自己本身。

    开始简单demo

    准备数据

    首先为了使用递归组件需要准备一份数据,因为这次是生成一个菜单,所以准备一个菜单书数据,新建一个testdata.js 文件代码如下

    var demoData = [
      {
        'id': '1',
        'menuName': '基础管理',
        'menuCode': '10',
        'children': [
          {
            'menuName': '用户管理',
            'menuCode': '11'
          },
          {
            'menuName': '角色管理',
            'menuCode': '12',
            'children': [
              {
                'menuName': '管理员',
                'menuCode': '121'
              },
              {
                'menuName': 'CEO',
                'menuCode': '122'
              },
              {
                'menuName': 'CFO',
                'menuCode': '123'
              },
              {
                'menuName': 'COO',
                'menuCode': '124'
              },
              {
                'menuName': '普通人',
                'menuCode': '124'
              }
            ]
          },
          {
            'menuName': '权限管理',
            'menuCode': '13'
          }
        ]
      },
      {
        'id': '2',
        'menuName': '商品管理',
        'menuCode': ''
      },
      {
        'id': '3',
        'menuName': '订单管理',
        'menuCode': '30',
        'children': [
          {
            'menuName': '订单列表',
            'menuCode': '31'
          },
          {
            'menuName': '退货列表',
            'menuCode': '32',
            'children': []
          }
        ]
      },
      {
        'id': '4',
        'menuName': '商家管理',
        'menuCode': '',
        'children': []
      }
    ];
    
    export default  demoData;
    
    
    

    这是使用时 ES6 语法,导出一个数据,所以这里必须注意 ES6 导出的语法,如果不清楚 ES6 的语法自行了解.

    建立树形组件

    现在建立树形组件,首先新建一个文件treeMenu,代码如下

    <template>
      <li>
        <span @click="toggle">
          <i v-if="hasChild" class="icon" v-bind:class="[open ? 'folder-open': 'folder' ]"></i>
          <i v-if="!hasChild" class="icon file-text"></i>
          {{model.menuName}}
        </span>
        <ul v-show="open" v-if="hasChild">
          <tree-menu v-for="(item,index) in model.children"  v-bind:model="item" v-bind:key="index"></tree-menu>
        </ul>
      </li>
    </template>
    
    <script>
      export default {
        name: "treeMenu",
        props: ['model'],
        data(){
          return {
            open:false
          }
        },
        computed:{
          hasChild(){
            return this.model.children && this.model.children.length
          }
        },
        methods:{
          toggle(){
            if(this.hasChild){
              this.open = !this.open
            }
          }
        }
      }
    </script>
    
    <style>
      ul {
        list-style: none;
        margin: 10px 0;
      }
    
      li {
        padding: 3px 0;
      }
    
      li > span {
        cursor: pointer;
        font-size: 14px;
        line-height: 20px;
      }
    
      i.icon {
        display: inline-block;
        width: 20px;
        height: 20px;
        margin-right: 5px;
        background-repeat: no-repeat;
        vertical-align: middle;
      }
    
      .icon.folder {
        background-image: url(/src/assets/folder.png);
      }
    
      .icon.folder-open {
        background-image: url(/src/assets/folder-open.png);
      }
    
      .icon.file-text {
        background-image: url(/src/assets/file-text.png);
      }
    
      .tree-menu li {
        line-height: 1.5;
      }
    </style>
    
    

    上述代码中我们需要注意,这个组件必须含有 name 这个属性,因为没有 name 这个属性会造成控件自身不能调用自身,自身调用的时候最好有绑定 key ,因为这个 key 是唯一的标识,对于 vue 更新控件比较好.除非控件非常简单就不用 key.

    另外一个需要注意就是递归组件时候,需要有一个条件来终止递归,在这里使用 v-for 隐形条件终止递归. props 这个属性其实主要传递父控件的数据的参数,具体用法可以参详 vue 的官方文档.

    sidebar 控件

    新建一个 sidebar 控件,代码如下

    <template>
      <div class="tree-menu">
        <ul v-for="menuItem in theModel">
          <my-tree :model="menuItem"></my-tree>
        </ul>
      </div>
    </template>
    
    <script>
      import testData from './testdata';
      import myTree from './treeMenu';
    
      export default {
        name: "side-bar",
        components: {
          myTree
        },
        data() {
          return {
            theModel: testData
          }
        }
      }
    </script>
    

    在把该 sidebar 组件添加到 HelloWorld.vue 中,成功后如下图:

    成功后会出现如下图的


    image.png

    参考文档

    Vue递归组件
    用Vue.js递归组件构建一个可折叠的树形菜单
    vuejs学习--递归组件(树型表格分享)

    相关文章

      网友评论

        本文标题:vue 递归组件

        本文链接:https://www.haomeiwen.com/subject/pkagnxtx.html