vue中使用递归组件创建导航菜单

概念

组件在它的模板内可以递归的调用自己,只要给组件设置name就可以了

用法

设置name后,在组件模板内就可以递归使用了,不过需要注意的是,必须给一个条件来限制递归数量,否则会抛出错误:max stack size exceeded

  • 父组件
    在父组件中定义一个要递归的数据(list数组),通过props传递给子组件
const vm = new Vue({
      el: '#app',
      data: {
        msg: '我是来自父组件数据',
        list: [
          {
            name: 1,
            clist: [
              {
                name: 2,
                clist: [
                  {
                    name: 3
                  }
                ]
              },
            ],
          },
        ]
      },
      created() { },
      methods: {

      }
    })
  • 子组件
    定义一个name为com的子组件
Vue.component('com', {
      template: `<div>
        <div v-for="(item, index) in list" :key="index">
          <p>{{item.name}}</p>
          <com :list="item.clist"></com>
        </div>
      </div>`,
      props: {
        list: {
          type: Array,
        }
      },
      data() {
        return {
          message: '我是子组件',
        };
      },
      created() { },
      methods: {},
    });

使用组件递归可以用来开发一些具有未知层级关系的独立组件,比如

  • 级联选择器
    在这里插入图片描述
  • 树形控件
    在这里插入图片描述
  • 导航菜单
    在这里插入图片描述
案例

使用递归组件创建导航菜单

  • 父组件
<template>
  <div class="nav">
    <el-aside class="aside" style="width:100%">
      <el-menu
        :default-active="active"
        class="el-menu-vertical-demo"
        background-color="#3A3D4C"
        text-color="#fff"
        active-text-color="#01a5a7"
        :collapse="isCollapse"
        unique-opened
        router
      >
        <NavItem v-for="v in navList" :key="v.path" :item="v" :basePath="v.path" :showIcon="true"></NavItem>
      </el-menu>
    </el-aside>
  </div>
</template>
<script>
import NavItem from "./NavItem";
export default {
  data() {
    return {
      isCollapse: false, // 是否水平折叠收起菜单
      active: "/home", // 高亮显示的路由
      navList: [
        {
          title: "首页",
          path: "/home",
          icon: "el-icon-menu",
        },
        {
          title: "vue",
          path: "",
          subMenu: [
            {
              title: "MVVM",
              path: "/mvvm",
            },
            {
              title: "过滤器",
              path: "/filter",
            },
            {
              title: "指令",
              path: "/directive",
            },
            {
              title: "按键修饰符",
              path: "/keyModifier",
            },
          ],
        },
        {
          title: "echarts图表",
          path: "/",
          subMenu: [
            {
              title: "折线图",
              path: "/lineEcharts",
            },
            {
              title: "K线图",
              path: "/kEcharts",
            },
          ],
        },
      ],
    };
  },
  components: {
    NavItem,
  },
  created() {
    // 刷新页面后,当前路由下的导航菜单高亮显示
    this.active = this.$route.path;
  },
  methods: {
    handleMenu() {
      this.isCollapse = !this.isCollapse;
      if (this.isCollapse) {
        this.$notify({
          title: "成功",
          message: "已折叠菜单栏",
          type: "success",
        });
      } else {
        this.$notify({
          title: "成功",
          message: "已打开菜单栏",
          type: "success",
        });
      }
    },
  },
};
</script>
<style scoped>
.aside {
  height: calc(100vh - 60px);
  color: #fff;
  box-sizing: border-box;
  overflow-x: hidden;
  /* 隐藏滚动条 */
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE 10+ */
}
/* 隐藏滚动条 */
::-webkit-scrollbar {
  display: none; /* Chrome Safari */
}
.menu {
  text-align: left;
}
</style>
<style>
.el-menu-vertical-demo {
  padding-top: 30px;
  height: calc(100vh - 60px);
  box-sizing: border-box;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 210px;
  min-height: 400px;
}
</style>
  • 子组件
<template>
  <!-- 使用fragment解决组件递归菜单栏不能折叠的问题 -->
  <!-- 递归的时候外面套了一层div(不套div不行模板没有根),element的css选择器就找不里面的span了和那个小箭头了 -->
  <!-- 因为element用的选择器是子类选择器一层一层找的,递归的时候多加了一层div,选择器就找不到了 -->
  <!-- 此处使用fragment代替div,因为fragment编码但不渲染成标签 -->
  <fragment>
    <!-- 无子集 -->
    <el-menu-item :index="basePath" v-if="!item.subMenu">
      <i :class="item.icon" v-if="showIcon"></i>
      <span slot="title">{{item.title}}</span>
    </el-menu-item>

    <!-- 有子集 -->
    <el-submenu :index="basePath" v-else>
      <template slot="title">
        <i class="el-icon-location"></i>
        <span>{{item.title}}</span>
      </template>
      <NavItem
        v-for="ite in item.subMenu"
        :key="ite.url"
        :item="ite"
        :basePath="ite.path"
        :showIcon="false"
      />
    </el-submenu>
  </fragment>
</template>
<script>
export default {
  name: "NavItem",
  data() {
    return {};
  },
  props: ["item", "basePath", "showIcon"],
};
</script>

前端进阶精选:点此去

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值