需求:使用 Vue + Antd 搭建后台管理系统,封装无限下拉循环菜单
文档:Antd
第一步:搭建Vue脚手架,这里不做过多叙述。
第二步:导入 Antd 依赖
npm install antd
第三步:新建菜单组件 SiderMenu.vue
<template>
<div style="width: 256px">
<a-menu
:selectedKeys="selectedKeys"
:openKeys.sync="openKeys"
mode="inline"
:theme="theme"
>
<template v-for="item in menuData">
<a-menu-item
v-if="!item.children"
:key="item.path"
@click="() => $router.push({ path: item.path, query: $route.query })"
>
<a-icon v-if="item.meta.icon" :type="item.meta.icon" />
<span>{{ item.meta.title }}</span>
</a-menu-item>
<sub-menu v-else :menu-info="item" :key="item.path" />
</template>
</a-menu>
</div>
</template>
<script>
import SubMenu from "./SubMenu";
import { check } from "../utils/auth";
export default {
props: {
theme: {
type: String,
default: "dark"
},
collapsed: {
type: Boolean,
default: false
}
},
components: {
"sub-menu": SubMenu
},
watch: {
"$route.path": function(val) {
this.selectedKeys = this.selectedKeysMap[val];
this.openKeys = this.collapsed ? [] : this.openKeysMap[val];
},
collapsed(val) {
if (val) {
this.cacheOpenKeys = this.openKeys;
this.openKeys = [];
} else {
this.openKeys = this.cacheOpenKeys;
}
}
},
data() {
this.selectedKeysMap = {};
this.openKeysMap = {};
const menuData = this.getMenuData(this.$router.options.routes);
return {
menuData,
selectedKeys: this.selectedKeysMap[this.$route.path],
openKeys: this.collapsed ? [] : this.openKeysMap[this.$route.path]
};
},
created() {
console.log(this.collapsed);
},
methods: {
toggleCollapsed() {
this.collapsed = !this.collapsed;
},
getMenuData(routes = [], parentKeys = [], selectedKey) {
const menuData = [];
for (let item of routes) {
if (item.meta && item.meta.authority && !check(item.meta.authority)) {
continue;
}
if (item.name && !item.hideInMenu) {
this.openKeysMap[item.path] = parentKeys;
this.selectedKeysMap[item.path] = [selectedKey || item.path];
const newItem = { ...item };
delete newItem.children;
if (item.children && !item.hideChildrenInMenu) {
newItem.children = this.getMenuData(item.children, [
...parentKeys,
item.path
]);
} else {
this.getMenuData(
item.children,
selectedKey ? parentKeys : [...parentKeys, item.path],
selectedKey || item.path
);
}
menuData.push(newItem);
} else if (
!item.hideInMenu &&
!item.hideChildrenInMenu &&
item.children
) {
menuData.push(
...this.getMenuData(item.children, [...parentKeys, item.path])
);
}
}
return menuData;
}
}
};
</script>
第四步:建立菜单中需要的下级菜单子组件 SubMenu.vue
<template functional>
<a-sub-menu :key="props.menuInfo.path">
<span slot="title">
<a-icon
v-if="props.menuInfo.meta.icon"
:type="props.menuInfo.meta.icon"
/><span>{{ props.menuInfo.meta.title }}</span>
</span>
<template v-for="item in props.menuInfo.children">
<a-menu-item
v-if="!item.children"
:key="item.path"
@click="
() =>
parent.$router.push({ path: item.path, query: parent.$route.query })
"
>
<a-icon v-if="item.meta.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-sub-menu>
</template>
<script>
export default {
props: ["menuInfo"]
};
</script>
备注:这里的菜单数据,是通过路由获取的,因此路由得按如下格式配置:
routes: [
{
path: "/",
hideInMenu: true,
component: () =>
import("@/views/Login.vue")
},
{
path: "/admin",
meta: { authority: ["user", "admin"] },
component: () =>import( "@/layouts/admin"),
children: [
{
path: "/",
redirect: "/dashboard/analysis"
},
{
path: "/dashboard/analysis",
name: "dashboard",
meta: { icon: "home", title: "首页" },
component: () =>
import( "@/views/Dashboard/Analysis")
},
]
}
]