Skip to content

六.导航(菜单)

前言 --> 菜单组件特点

递归组件就是组件在模板中调用自己,需要满足两个条件:

  • 在组件中设置一个name选项,通过这个字段拿到组件
  • 加上结束条件,防止一直递归下去,抛出max stack size exeeded错误

1.目录结构

sh
├── table                      
   ├── dropdown-item.vue       
   ├── dropdown-menu.vue           
   ├── dropdown.vue                 
   └── index.js

1.实现方式

vue
<template>
  <my-component :count="count + 1" v-if="count <= 5"></my-component> <!-- 2.添加限定条件 -->
</template>
<script>
export default {
  name: "my-component", // 1.添加名称标识
  props: {
    count: {
      type: Number,
      default: 1,
    },
  },
}
</script>

提示

递归组件常用来开发具有位置层级关系的独立组件,这类组件一般都是数据驱动型的,父级有一个字段 children,然后递归

2.使用案例

使用 vue 的递归组件写一个菜单组件,实现无限菜单

App.vue 案例
vue
<template>
  <div id="app">
    <Menu>
      <template v-for="menu in menuList">
        <MenuItem :key="menu.title" v-if="!menu.children">
          {{ menu.title }}
        </MenuItem>
        <ReSubMenu :key="menu.title" v-else :data="menu"></ReSubMenu>
      </template>
    </Menu>
  </div>
</template>

<script>
import Menu from "./Menu"
import MenuItem from "./MenuItem"
import SubMenu from "./SubMenu"
import ReSubMenu from "./ReSubMenu"
export default {
  data() {
    return {
      msg: "hello",
      menuList: [
        {
          title: "菜单1",
          children: [
            {
              title: "菜单1-1",
              children: [
                { title: "菜单1-1-1" },
                { title: "菜单1-1-2" },
                {
                  title: "菜单1-1-3",
                  children: [
                    { title: "菜单1-1-1" },
                    { title: "菜单1-1-2" },
                    {
                      title: "菜单1-1-3",
                      children: [
                        { title: "菜单1-1-1" },
                        { title: "菜单1-1-2" },
                        {
                          title: "菜单1-1-3",
                          children: [
                            { title: "菜单1-1-1" },
                            { title: "菜单1-1-2" },
                            { title: "菜单1-1-3" },
                          ],
                        },
                      ],
                    },
                  ],
                },
              ],
            },
            { title: "菜单1-2" },
            { title: "菜单1-3" },
          ],
        },
        {
          title: "菜单2",
        },
        {
          title: "菜单3",
        },
      ],
    }
  },
  components: {
    Menu,
    MenuItem,
    SubMenu,
    ReSubMenu,
  },
}
</script>
<style>
#app {
  color: red;
}
</style>
  • Menu.vue
vue
<template>
  <ul class="menu">
    <slot></slot>
  </ul>
</template>
  • MenuItem
vue
<template>
  <li>
    <slot></slot>
  </li>
</template>
  • ReSubMenu.vue
vue
<template>
  <SubMenu>
    <template #title>
      {{ data.title }}
    </template>
    <template v-for="child in data.children">
      <!-- 如果没儿子 直接渲染MenuItem 如果有儿子 将儿子递归传入 -->
      <MenuItem :key="child.title" v-if="!child.children">{{
        child.title
      }}</MenuItem>
      <ReSub v-else :key="child.title" :data="child"></ReSub>
    </template>
  </SubMenu>
</template>
<script>
import SubMenu from "./SubMenu"
import MenuItem from "./MenuItem"
export default {
  name: "ReSub", //可以使用递归组件
  props: {
    data: {
      type: Object,
      default: () => ({}),
    },
  },
  components: {
    SubMenu,
    MenuItem,
  },
}
</script>
  • SubMenu.vue
vue
<template>
  <div>
    <div class="title" @click="change">
      <slot name="title"></slot>
    </div>
    <div v-show="flag" class="sub">
      <slot></slot>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return { flag: false }
  },
  methods: {
    change() {
      this.flag = !this.flag
    },
  },
}
</script>
<style>
.sub {
  padding-left: 10px;
}
</style>

3.使用场景

<template>
    <vue-button>按钮</vue-button>
</template>

总结

合理使用动态组件可以让我们写出的代码更加简洁,减少冗余代码