是什么为什么怎么做

递归组件就是指组件在模板中调用自己,开启递归组件的必要条件,就是在组件中设置一个 name 选项
以后天管理的左侧菜单栏为例
代码如下:

  1. // menu/index.vue
  2. <template>
  3. <template v-for="(item, index) in menuList" :key="item.path">
  4. <!-- 没有子路由 -->
  5. <template v-if="!item.children">
  6. <el-menu-item v-if="!item.meta.hidden" :index="item.path">
  7. <template #title>
  8. <span>标&nbsp;</span>
  9. <span>{{ item.meta.title }}</span>
  10. </template>
  11. </el-menu-item>
  12. </template>
  13. <!-- 有子路由,但是只有一个 -->
  14. <template v-if="item.children && item.children.length == 1">
  15. <el-menu-item v-if="!item.children[0].meta.hidden" :index="item.children[0].path">
  16. <template #title>
  17. <span>{{ item.children[0].meta.title }}</span>
  18. </template>
  19. </el-menu-item>
  20. </template>
  21. <!-- 有子路由,且个数大于1 -->
  22. <el-sub-menu :index="item.path" v-if="item.children && item.children.length > 1">
  23. <template #title>
  24. <span>{{ item.meta.title }}</span>
  25. </template>
  26. <!-- 递归组件 -->
  27. <Menu :menuList="item.children"></Menu>
  28. </el-sub-menu>
  29. </template>
  30. </template>
  31. <script lang="ts">
  32. import { defineComponent } from 'vue'
  33. export default defineComponent({
  34. name: 'Menu',
  35. })
  36. </script>
  37. <script lang="ts" setup>
  38. // 接受父组件传递的全部路由数据
  39. defineProps(['menuList'])
  40. </script>
  41. <style lang="scss" scoped></style>

在进行递归组件是,主要使用的是插槽来实现数据的传递。

  1. // layout/index.vue
  2. // 样式变量是在style文件中定义的变量
  3. <template>
  4. <div class="layout_container">
  5. <!-- 左侧菜单 -->
  6. <div class="layout_slider">
  7. <Logo></Logo>
  8. <!-- 展示菜单 -->
  9. <!-- 滚动组件 -->
  10. <el-scrollbar class="scrollbar">
  11. <!-- 菜单组件 -->
  12. <el-menu background-color="#001529" text-color="#fff">
  13. <Menu :menuList="userStore.menuRoutes"></Menu>
  14. </el-menu>
  15. </el-scrollbar>
  16. </div>
  17. <!-- 顶部导航 -->
  18. <div class="layout_tabbar">456</div>
  19. <!-- 内容展示区 -->
  20. <div class="layout_main">
  21. <!-- <p style="height: 3000px">789</p> -->
  22. </div>
  23. </div>
  24. </template>
  25. <script lang="ts">
  26. import { defineComponent } from 'vue'
  27. export default defineComponent({
  28. name: 'Layout',
  29. })
  30. </script>
  31. <script lang="ts" setup>
  32. // 引入左侧菜单子组件
  33. import Logo from './logo/index.vue'
  34. // 引入菜单组件
  35. import Menu from './menu/index.vue'
  36. // 获取用户相关的小仓库
  37. import useUserStore from '@/store/user'
  38. const userStore = useUserStore()
  39. </script>
  40. <style lang="scss" scoped>
  41. .layout_container {
  42. width: 100%;
  43. height: 100vh;
  44. // background-color: #e84a4a;
  45. .layout_slider {
  46. width: $base-menu-width;
  47. height: 100vh;
  48. background-color: $base-menu-background;
  49. .scrollbar {
  50. width: 100%;
  51. height: calc(100vh - $base-menu-logo-height);
  52. .el-menu {
  53. border-right: none;
  54. }
  55. }
  56. }
  57. .layout_tabbar {
  58. position: fixed;
  59. top: 0px;
  60. left: $base-menu-width;
  61. width: calc(100% - $base-menu-width);
  62. height: $base-tabber-height;
  63. background-color: #45c1ea;
  64. }
  65. .layout_main {
  66. position: absolute;
  67. width: calc(100% - $base-menu-width);
  68. height: calc(100vh - $base-tabber-height);
  69. background-color: #48ca62;
  70. left: $base-menu-width;
  71. top: $base-tabber-height;
  72. padding: 20px;
  73. overflow: auto;
  74. }
  75. }
  76. </style>

插槽

插槽又分为具名插槽、匿名插槽、自定义插件,经常用于组件的封装