在Vue3 jsx 语法中使用 v-slots 插槽 和 component动态组件,实现一个递归遍历循环渲染的多层级菜单

前言

相信大家在使用vue3开发项目过程中肯定用到过 slots 插槽和 component 动态组件来封装一些业务组件吧,但大多数情况下都是在template 模板语法中去使用的。下面给大家分享一下我个人在项目开发过程中在vue3 jsx语法中去使用 v-slotscomponent 去封装一个递归循环的管理系统多层级菜单

首先看看在 template 模板语法中 slots 和component 是如何使用的

1.原template语法中使用 slot 插槽是通过 #title#icon 方式实现

2.动态组件通过component 方式实现

javascript 复制代码
<template>
  <a-menu>
    <a-sub-menu key="sub1" @titleClick="titleClick">
      <template #icon>
         <component :is="QqOutlined "></component >
      </template>
      <template #title>Navigation One</template>
      <a-menu-item-group key="g1">
        <template #icon>
          <component :is="QqOutlined "></component >
        </template>
        <template #title>Item 1</template>
        <a-menu-item key="1">Option 1</a-menu-item>
        <a-menu-item key="2">Option 2</a-menu-item>
      </a-menu-item-group>
      <a-menu-item-group key="g2" title="Item 2">
        <a-menu-item key="3">Option 3</a-menu-item>
        <a-menu-item key="4">Option 4</a-menu-item>
      </a-menu-item-group>
    </a-sub-menu>
  </a-menu>
</template>

而在jsx语法中插槽和动态组件的使用方法则有很大的不同

1.使用 v-slots 接收插槽参数 default 为默认插槽titleicon为ui组件的作用域插槽

2.动态的实现需要使用 hresolveComponent 这两个组合式api

javascript 复制代码
   const slot = {
       title: () => <span> {menu.meta.title}</span>,
       icon: () => (
         <span>{menu.meta.icon ? h(resolveComponent(menu.meta.icon)) : ""} </span>
       ),
     };
     <a-menu
       mode="inline"
       theme="dark"
       forceSubMenuRender={true}
     >
     <a-sub-menu key={menu.name} v-slots={slot}>
        <a-menu-item key={menu.name}>
           菜单内容
       </a-menu-item>
       </a-sub-menu>
     </a-menu>

完整的代码deom,实现一个menu递归遍历循环渲染的菜单

javascript 复制代码
<script>
import { useStore } from "vuex";
import { useRoute } from "vue-router";
import { computed, ref, watch, h, resolveComponent, defineComponent } from "vue";
export default defineComponent({
  setup() {
    const store = useStore();
    const route = useRoute();
    //当前选中项
    const selectedKeys = ref([route.name]);
    //当前展开项
    const openKeys = ref([route.meta.partentName || ""]);
    const menuTrees = computed(() => store.state.permission.addRouters);
    watch(route, (n, o) => {
      selectedKeys.value = [n.name];
    });

    // 生成 subMenu 菜单
    const renderSubMenu = (menu) => {
      const menuItem = [];
      menu.children.forEach((item) => menuItem.push(renderMenu(item)));
      const slot = {
        title: () => <span> {menu.meta.title}</span>,
        icon: () => (
          <span>{menu.meta.icon ? h(resolveComponent(menu.meta.icon)) : ""} </span>
        ),
      };
      return (
        <a-sub-menu key={menu.name} v-slots={slot}>
          {menuItem}
        </a-sub-menu>
      );
    };
    // 生成  menu-item 菜单
    const renderMenuItem = (menu) => {
      const slot = {
        icon: () => (
          <span>{menu.meta.icon ? h(resolveComponent(menu.meta.icon)) : ""} </span>
        ),
      };
      return (
        <a-menu-item key={menu.name} v-slots={slot}>
          <router-link to={menu.path}>{menu.meta.title}</router-link>
        </a-menu-item>
      );
    };

    const renderMenu = (menu) => {
      return menu.children ? renderSubMenu(menu) : renderMenuItem(menu);
    };

    const menuList = menuTrees.value.map((menu) => {
      return renderMenu(menu);
    });
    return () => (
      <a-menu
        mode="inline"
        theme="dark"
        forceSubMenuRender={true}
        v-model:selectedKeys={selectedKeys.value}
        v-model:openKeys={openKeys.value}
      >
        {menuList}
      </a-menu>
    );
  },
});
</script>

效果图:

如果当前脚手架不支持 jsx语法的编译 需要安装支持 jsx语法的包
javascript 复制代码
npm i @vitejs/plugin-vue-jsx -s

完整的项目代码地址可参考:gitee.com/ZHANG_6666/...

相关推荐
weixin_382395239 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__9 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.10 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~11 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华12 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子14 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅14 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni14 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学16 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端