说明
【Vue 开发实战】学习笔记。
实现效果
BasicLayout.vue
<template> <div :class="[`nav-theme-${navTheme}`, `nav-layout-${navLayout}`]"> <a-layout id="components-layout-demo-side" style="min-height: 100vh"> <a-layout-sider v-if="navLayout === 'left'" v-model="collapsed" width="256px" collapsible :theme="navTheme" :trigger="null" > <div class="logo">Ant Design Vue Pro</div> <SiderMenu :theme="navTheme"/> </a-layout-sider> <a-layout> <a-layout-header style="background: #fff; padding: 0"> <a-icon class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="collapsed = !collapsed" ></a-icon> <Header /> </a-layout-header> <a-layout-content style="margin: 0 16px"> <router-view></router-view> </a-layout-content> <a-layout-footer style="text-align: center"> <Footer /> </a-layout-footer> </a-layout> </a-layout> <SettingDrawer /> </div> </template> <script> import Header from "./Header"; import SiderMenu from "./SiderMenu"; import Footer from "./Footer"; import SettingDrawer from "../components/SettingDrawer"; export default { data() { return { collapsed: false, }; }, components: { Header, SiderMenu, Footer, SettingDrawer, }, computed: { navTheme() { return this.$route.query.navTheme || "dark"; }, navLayout() { return this.$route.query.navLayout || "left"; }, }, }; </script> <style lang="less" scoped> .trigger { padding: 0 20px; line-height: 64px; font-size: 20px; &:hover { background-color: #eeeeee; } } .logo { height: 64px; line-height: 64px; text-align: center; overflow: hidden; } .nav-theme-dark { .logo { color: #fff; } } </style>
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: $router.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-menu> </div> </template> <script> import SubMenu from "./SubMenu.vue"; export default { props: { theme: { type: String, default: "dark" } }, components: { "sub-menu": SubMenu }, data() { this.selectedKeysMap = {}; this.openKeysMap = {}; const menuData = this.getMenuData(this.$router.options.routes) return { collapsed: false, menuData, selectedKeys: this.selectedKeysMap[this.$route.path], openKeys: this.collapsed ? [] : this.openKeysMap[this.$route.path] }; }, watch: { "$route.path": function(val) { this.selectedKeys = this.selectedKeysMap[val]; this.openKeys = this.collapsed ? [] : this.openKeysMap[val]; } }, methods: { getMenuData(routes = [], parentKeys = [], selectedKeys) { const menuData = []; routes.forEach(item => { if(item.name && !item.hideInMenu) { this.openKeysMap[item.path] = parentKeys; this.selectedKeysMap[item.path] = [selectedKeys || 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, selectedKeys ? parentKeys : [...parentKeys, item.path], selectedKeys || 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.$router.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>
路由配置
import Vue from "vue"; import VueRouter from "vue-router"; import NProgress from "nprogress"; import "nprogress/nprogress.css"; import NotFound from "../views/404"; Vue.use(VueRouter); const routes = [ { path: "/user", hideInMenu: true, component: () => import(/* webpackChunkName: "layout" */ "../layouts/UserLayout"), children: [ { path: "/user", redirect: "/user/login" }, { path: "/user/login", name: "login", component: () => import(/* webpackChunkName: "user" */ "../views/User/Login"), }, { path: "/user/register", name: "register", component: () => import(/* webpackChunkName: "user" */ "../views/User/Register"), } ], }, { path: "/", component: () => import(/* webpackChunkName: "layout" */ "../layouts/BasicLayout"), children: [ { path: "/", redirect: "/dashboard" }, { path: "/dashboard", redirect: "/dashboard/analysis" }, { path: "/dashboard", name: "dashboard", meta: { icon: "dashboard", title: "仪表盘" }, component: { render: h => h("router-view")}, children: [ { path: "/dashboard/analysis", name: "analysis", meta: { title: "分析页" }, component: () => import(/* webpackChunkName: "dashboard" */ "../views/Dashboard/Analysis"), }, ] }, { path: "/form", name: "form", meta: { icon: "form", title: "表单" }, component: { render: h => h("router-view")}, children: [ { path: "/form", redirect: "/form/basic-form" }, { path: "/form/basic-form", name: "basicform", meta: { title: "基础表单" }, component: () => import(/* webpackChunkName: "form" */ "../views/Forms/BasicForm"), }, { path: "/form/step-form", name: "stepform", hideChildrenInMenu: true, meta: { title: "分步表单" }, component: () => import(/* webpackChunkName: "form" */ "../views/Forms/StepForm"), children: [ { path: "/form/step-form", redirect: "/form/step-form/info" }, { path: "/form/step-form/info", name: "info", component: () => import(/* webpackChunkName: "form" */ "../views/Forms/StepForm/Step1"), }, { path: "/form/step-form/confirm", name: "confirm", component: () => import(/* webpackChunkName: "form" */ "../views/Forms/StepForm/Step2"), }, { path: "/form/step-form/result", name: "result", component: () => import(/* webpackChunkName: "form" */ "../views/Forms/StepForm/Step3"), }, ] }, ] } ], }, { path: "*", name: "404", hideInMenu: true, component: NotFound } ]; const router = new VueRouter({ mode: "history", base: process.env.BASE_URL, routes }); // 路由守卫 router.beforeEach((to, from, next) => { if(to.path !== from.path) { NProgress.start(); } next(); }) router.afterEach((to, from) => { NProgress.done(); }) export default router;