zoukankan      html  css  js  c++  java
  • Vue.js 递归组件实现树形菜单

    最近看了 Vue.js 的递归组件,实现了一个最基本的树形菜单。

    main.js 作为入口:

    import Vue from 'vue'
    import main from './components/main.vue'
    
    new Vue({
      el: '#app',
      render: h => h(main)
    })
    

    它引入了一个组件 main.vue:

    <template>
      <div>
        <my-tree :data="theData" :name="menuName" :loading="loading" @getSubMenu="getSubMenu"></my-tree>
      </div>
    </template>
    
    <script>
    const myData = [
      {
        id: '1',
        menuName: '基础管理',
        menuCode: '10'
      },
      {
        id: '2',
        menuName: '商品管理',
        menuCode: ''
      },
      {
        id: '3',
        menuName: '订单管理',
        menuCode: '30',
        children: [
          {
            menuName: '订单列表',
            menuCode: '31'
          },
          {
            menuName: '退货列表',
            menuCode: '32',
            children: []
          }
        ]
      },
      {
        id: '4',
        menuName: '商家管理',
        menuCode: '',
        children: []
      }
    ];
    
    const subMenuData1 = {
      parentId: '1',
      children: [
        {
          menuName: '用户管理',
          menuCode: '11'
        },
        {
          id: '12',
          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'
        }
      ]
    };
    
    const subMenuData2 = {
      parentId: '2',
      children: [
        {
          menuName: '商品一',
          menuCode: '21'
        },
        {
          id: '22',
          menuName: '商品二',
          menuCode: '22',
          children: [
            {
              menuName: '子类商品1',
              menuCode: '221'
            },
            {
              menuName: '子类商品2',
              menuCode: '222'
            }
          ]
        }
      ]
    };
    
    import myTree from './common/treeMenu.vue'
    export default {
      components: {
        myTree
      },
      data () {
        return {
          theData: myData,
          menuName: 'menuName', // 显示菜单名称的属性
          loading: false
        }
      },
      methods: {
        getSubMenu (menuItem, callback) {
          this.loading = true;
    
          if (menuItem.id === subMenuData1.parentId) {
            this.loading = false;
            menuItem.children = subMenuData1.children;
            callback(menuItem.children);
          }
    
          setTimeout(() => {
            if (menuItem.id === subMenuData2.parentId) {
              this.loading = false;
              menuItem.children = subMenuData2.children;
              callback(menuItem.children);
            }
          }, 2000);
        }
      }
    }
    </script>

     subMenuData1, subMenuData2 存放子菜单数据,可以从服务器获取,以实现动态加载。

    该文件引入了树形组件 treeMenu.vue:

    <template>
      <ul class="tree-menu">
        <li v-for="(item, index) in data">
          <span @click="toggle(item, index)">
            <i :class="['icon', item.children && item.children.length ? folderIconList[index] : 'file-text', loading ? loadingIconList[index] : '']"></i>
            {{ item[name] || item.menuName }}
          </span>
          <tree-menu v-if="scope[index]" :data="item.children"></tree-menu>
        </li>
      </ul>
    </template>
    
    <script>
    export default {
      name: 'treeMenu',
      props: {
        data: Array,
        name: String,
        loading: Boolean
      },
      data () {
        return {
          folderIconList: [],
          loadingIconList: [],
          scope: {}
        }
      },
      created () {
        this.data.forEach((item, index) => {
          if (item.children && item.children.length) {
            this.folderIconList[index] = 'folder';
          }
        });
      },
      methods: {
        doTask (index) {
          this.$set(this.scope, index, !this.scope[index]);
          this.folderIconList[index] = this.scope[index] ? 'folder-open' : 'folder';
        },
        toggle (item, index) {
          this.loadingIconList = [];
    
          if (item.children && item.children.length) {
            this.doTask(index);
          } else {
            this.loadingIconList[index] = 'loading';
    
            this.$emit('getSubMenu', item, (subMenuList) => {
              if (subMenuList && subMenuList.length) {
                this.doTask(index);
              }
            });
          }
        }
      }
    }
    </script>
    
    <style scoped>
    .tree-menu {
      list-style: none;
    }
    .tree-menu li {
      line-height: 2;
    }
    .tree-menu li span {
      cursor: default;
    }
    .icon {
      display: inline-block;
       15px;
      height: 15px;
      background-repeat: no-repeat;
      vertical-align: -2px;
    }
    .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);
    }
    .icon.loading {
      background-image: url(/src/assets/loading.gif);
      background-size: 15px;
    }
    </style>

    效果图:

    示例代码放在这里

  • 相关阅读:
    Oracle--pl/sql编程-分支语句(判断、循环)
    axios二次封装及API接口统一管理
    Vuejs之axios获取Http响应头
    对webpack和gulp的理解和区别
    nodejs+redis使用
    Linux安装Nginx、Redis、django
    js 原型里面写方法
    在layui中使用 jquery 触发select 的 change事件无效
    promise看这篇就够了
    vue 封装原型方法 加 promist .then
  • 原文地址:https://www.cnblogs.com/caihg/p/6208105.html
Copyright © 2011-2022 走看看