1、根据list值生成静态菜单代码

SiderMenu.vue

<template>
  <div>
    <a-button type="primary" style="margin-bottom: 16px"> LOGO </a-button>
    <a-menu
      :default-selected-keys="['1']"
      :default-open-keys="['2']"
      mode="inline"
      :theme="theme"
      :inline-collapsed="collapsed"
    >
      <template v-for="item in list">
        <a-menu-item v-if="!item.children" :key="item.key">
          <a-icon type="pie-chart" />
          <span>{{ item.title }}</span>
        </a-menu-item>
        <sub-menu v-else :key="item.key + '1'" :menu-info="item" />
      </template>
    </a-menu>
  </div>
</template>

<script>
import { mapState } from "vuex";
import { Menu } from "ant-design-vue";
const SubMenu = {
  template: `
      <a-sub-menu :key="menuInfo.key" v-bind="$props" v-on="$listeners">
        <span slot="title">
          <a-icon type="mail" /><span>{{ menuInfo.title }}</span>
        </span>
        <template v-for="item in menuInfo.children">
          <a-menu-item v-if="!item.children" :key="item.key">
            <a-icon type="pie-chart" />
            <span>{{ item.title }}</span>
          </a-menu-item>
          <sub-menu v-else :key="item.key" :menu-info="item" />
        </template>
      </a-sub-menu>
    `,
  name: "SubMenu",
  // must add isSubMenu: true
  isSubMenu: true,
  props: {
    ...Menu.SubMenu.props,
    // Cannot overlap with properties within Menu.SubMenu.props
    menuInfo: {
      type: Object,
      default: () => ({}),
    },
  },
};
export default {
  components: {
    "sub-menu": SubMenu,
  },
  props: {
    theme: {
      type: String,
      default: "dark",
    },
  },
  data() {
    return {
      list: [
        {
          key: "1",
          title: "Option 1",
        },
        {
          key: "2",
          title: "Navigation 2",
          children: [
            {
              key: "2.1",
              title: "Navigation 2.1",
              children: [{ key: "2.1.1", title: "Option 2.1.1" }],
            },
          ],
        },
        {
          key: "3",
          title: "Navigation 3",
          children: [
            {
              key: "3.1",
              title: "Navigation 3.1",
            },
          ],
        },
      ],
    };
  },
  computed: {
    ...mapState(["collapsed"]),
  },
  mounted() {},
  methods: {},
};
</script>
<style lang="less" scoped></style>

vue 报错 You are using the runtime-only build of Vue where the template compiler is not available.

vue.config.js

module.exports = {
  runtimeCompiler: true
}

2、根据路由生成动态菜单

SiderMenu.vue

<template>
  <div>
    <a-button type="primary" style="margin-bottom: 16px"> LOGO </a-button>
    <a-menu
      :default-selected-keys="[$route.path]"
      :default-open-keys="['/'+ $route.path.split('/')[1]]"
      mode="inline"
      :theme="theme"
      :inline-collapsed="collapsed"
      @click="onClick"
    >
      <template v-for="item in menu">
        <a-menu-item v-if="!item.children" :key="item.path">
          <a-icon :type="item.meta.icon" />
          <span>{{ item.meta.title }}</span>
        </a-menu-item>
        <sub-menu v-else :key="item.path " :menu-info="item" />
      </template>
    </a-menu>
  </div>
</template>

<script>
import { mapState } from "vuex";
import { Menu } from "ant-design-vue";
const SubMenu = {
  template: `
      <a-sub-menu :key="menuInfo.key" v-bind="$props" v-on="$listeners">
        <span slot="title">
          <a-icon :type="menuInfo.meta.icon" /><span>{{ menuInfo.meta.title }}</span>
        </span>
        <template v-for="item in menuInfo.children">
          <a-menu-item v-if="!item.children" :key="item.path">
            <span>{{ item.meta.title }}</span>
          </a-menu-item>
          <sub-menu v-else :key="item.key" :menu-info="item" />
        </template>
      </a-sub-menu>
    `,
  name: "SubMenu",
  // must add isSubMenu: true
  isSubMenu: true,
  props: {
    ...Menu.SubMenu.props,
    // Cannot overlap with properties within Menu.SubMenu.props
    menuInfo: {
      type: Object,
      default: () => ({}),
    },
  },
};
export default {
  components: {
    "sub-menu": SubMenu,
  },
  props: {
    theme: {
      type: String,
      default: "dark",
    },
  },
  data() {
    return {
      menu: [],
    };
  },
  computed: {
    ...mapState(["collapsed"]),
  },
  mounted() {
    // 根据路由获取菜单数据
    this.getMenuData(this.$router.options.routes, this.menu);
  },
  methods: {
    getMenuData(routes, arr) {
      routes.forEach((el) => {
        if (!el.hiden) {
          arr.push(el);
          if (el.children) {
            // 这里使用一个变量接收子数组作为递归的数据源
            // 将item.children置空用来接收不隐藏的数据
            let a = el.children;
            el.children = [];
            this.getMenuData(a, el.children);
          }
        }
      });
      return arr;
    },
    onClick(item) {
      this.$router.push(item.key);
    },
  },
};
</script>
<style lang="less" scoped></style>

路由文件 router/index.js

import Vue from "vue";
import VueRouter from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    redirect: "/home",
    meta: {
      icon: "weibo",
      title: "首页",
    },
    component: () => import("@/layouts/BasicLayout"),
    children: [
      {
        path: "/home",
        name: "home",
        meta: {
          icon: "weibo",
          title: "首页",
        },
        component: () => import("@/views/Home/Home"),
      },
    ],
  },
  {
    path: "/order",
    name: "order",
    meta: {
      icon: "apple",
      title: "订单",
    },
    component: () => import("@/layouts/BasicLayout"),
    children: [
      {
        path: "/order/list",
        name: "orderlist",
        meta: {
          icon: "apple",
          title: "订单列表",
        },
        component: () => import("@/views/Order/OrderList"),
        children: [
          {
            path: "/order/list/list1",
            name: "list1",
            component: () => import("@/views/Order/list1"),
            meta: {
              icon: "weibo",
              title: "list1",
            },
          },
          {
            path: "/order/list/list2",
            name: "list2",
            component: () => import("@/views/Order/list2"),
            meta: {
              icon: "weibo",
              title: "list1",
            },
          }
        ],
      },
      {
        path: "/order/detail",
        name: "orderdetail",
        hiden: true,
        meta: {
          title: "订单详情",
        },
        component: () => import("@/views/Order/OrderDetail"),
      },
      {
        path: "/order/comment",
        name: "ordercomment",
        meta: {
          title: "订单评论",
        },
        component: () => import("@/views/Order/OrderComment"),
      },
    ],
  },
  {
    path: "/my",
    name: "my",
    meta: {
      icon: "weibo",
      title: "我的",
    },
    component: () => import("@/layouts/BasicLayout"),
    children: [
      {
        path: "/my/index",
        name: "myinfo",
        component: () => import("@/views/My/My"),
        meta: {
          icon: "weibo",
          title: "我的",
        },
      },
    ],
  },
  {
    path: "/user",
    component: { render: (h) => h("router-view") },
    redirect: "/user/login",
    hiden: true,
    children: [
      {
        path: "/user/login",
        name: "Login",
        component: () => import("@/views/User/Login"),
      },
      {
        path: "/user/register",
        name: "Register",
        component: () => import("@/views/User/Register"),
      },
    ],
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to, from, next) => {
  NProgress.start();
  next();
});
router.afterEach(() => {
  NProgress.done();
});

export default router;

Logo

前往低代码交流专区

更多推荐