组件封装
为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度。
组件结构
组件封装重构后,试图组件结构如下图所示
代码一览
Home组件被简化,包含导航、头部和主内容三个组件。
Home.vue
<template><div class="container"><!-- 导航菜单栏 --><MenuBar></MenuBar><!-- 头部区域 --><HeadBar></HeadBar><!-- 主内容区域 --><Main></Main></div> </template><script> import HeadBar from "./HeadBar/HeadBar" import MenuBar from "./MenuBar/MenuBar" import Main from "./Main/Main" export default {components:{HeadBar,MenuBar,Main} }; </script><style scoped lang="scss">.container {position:absolute;top: 0px;left: 0px;right: 0px;background: #4b5f6e;} </style>
HeadBar.vue
<template> <div class="container"><!-- 导航菜单隐藏显示切换 --><span class="collapse-switcher" @click.prevent="collapse"><i class="el-icon-menu"></i></span><!-- 导航菜单 --><span class="nav-bar"><el-menu :default-active="activeIndex" class="el-menu-demo" text-color="#fff"active-text-color="#ffd04b" mode="horizontal" @select="selectNavBar()"><el-menu-item index="1" @click="$router.push('/')">{{$t("common.home")}}</el-menu-item><el-menu-item index="2">{{$t("common.doc")}}</el-menu-item><el-menu-item index="3">{{$t("common.msgCenter")}}</el-menu-item></el-menu></span><span class="tool-bar"><!-- 主题切换 --><ThemePicker class="theme-picker"></ThemePicker><!-- 语言切换 --><LangSelector class="lang-selector"></LangSelector> <!-- 用户信息 --><el-dropdown class="user-info-dropdown" trigger="hover"><span class="el-dropdown-link"><img :src="this.userAvatar" /> {{username}}</span><el-dropdown-menu slot="dropdown"><el-dropdown-item>{{$t("common.myMsg")}}</el-dropdown-item><el-dropdown-item>{{$t("common.config")}}</el-dropdown-item><el-dropdown-item divided @click.native="logout">{{$t("common.logout")}}</el-dropdown-item></el-dropdown-menu></el-dropdown></span></div> </template><script> import mock from "@/mock/index.js"; import ThemePicker from "@/components/ThemePicker" import LangSelector from "@/components/LangSelector" export default {components:{ThemePicker,LangSelector},data() {return {isCollapse: false,username: "Louis",userAvatar: "",activeIndex: '1'};},methods: {selectNavBar(key, keyPath) {console.log(key, keyPath)},// 语言切换handleCommand(command) {let array = command.split(':')let lang = array[0] === '' ? 'zh_cn' : array[0]let label = array[1]document.getElementById("language").innerHTML = labelthis.$i18n.locale = lang},//折叠导航栏collapse: function() {this.isCollapse = !this.isCollapse;},//退出登录logout: function() {var _this = this;this.$confirm("确认退出吗?", "提示", {type: "warning"}).then(() => {sessionStorage.removeItem("user");this.$router.push("/login");}).catch(() => {});}},mounted() {this.sysName = "I like Kitty";var user = sessionStorage.getItem("user");if (user) {this.userName = user;this.userAvatar = require("@/assets/user.png");}} }; </script><style scoped lang="scss"> .container {position: absolute;left: 200px;right: 0px;height: 60px;line-height: 60px;.collapse-switcher {width: 40px;float: left;cursor: pointer;border-color: rgba(111, 123, 131, 0.8);border-left-width: 1px;border-left-style: solid;border-right-width: 1px;border-right-style: solid;color: white;background: #504e6180;}.nav-bar {margin-left: auto;float: left;.el-menu {background: #504e6180;}}.tool-bar {float: right;.theme-picker {padding-right: 10px;}.lang-selector {padding-right: 10px;font-size: 15px;color: #fff;cursor: pointer;}.user-info-dropdown {font-size: 20px;padding-right: 20px;color: #fff;cursor: pointer;img {width: 40px;height: 40px;border-radius: 10px;margin: 10px 0px 10px 10px;float: right;}}} } </style>
MenuBar.vue
<template><div class="menu-bar-container"><!-- logo --><div class="logo" :class="isCollapse?'menu-bar-collapse-width':'menu-bar-width'"><img :src="this.logo" /> <div>{{isCollapse?'':sysName}}</div></div><!-- 导航菜单 --><el-menu default-active="1-1" :class="isCollapse?'menu-bar-collapse-width':'menu-bar-width'" @open="handleopen" @close="handleclose" @select="handleselect" :collapse="isCollapse"><el-submenu index="1"><template slot="title"><i class="el-icon-location"></i><span slot="title">{{$t("sys.sysMng")}}</span></template><el-menu-item index="1-1" @click="$router.push('user')">{{$t("sys.userMng")}}</el-menu-item><el-menu-item index="1-2" @click="$router.push('dept')">{{$t("sys.deptMng")}}</el-menu-item><el-menu-item index="1-3" @click="$router.push('role')">{{$t("sys.roleMng")}}</el-menu-item><el-menu-item index="1-4" @click="$router.push('menu')">{{$t("sys.menuMng")}}</el-menu-item><el-menu-item index="1-5" @click="$router.push('log')">{{$t("sys.logMng")}}</el-menu-item></el-submenu><el-submenu index="2"><template slot="title"><i class="el-icon-location"></i><span slot="title">{{$t("sys.sysMonitor")}}</span></template></el-submenu><el-menu-item index="3" disabled><i class="el-icon-document"></i><span slot="title">{{$t("sys.nav3")}}</span></el-menu-item><el-menu-item index="4"><i class="el-icon-setting"></i><span slot="title">{{$t("sys.nv4")}}</span></el-menu-item></el-menu></div> </template><script> export default {data() {return {isCollapse: false,sysName: "",logo: "",};},methods: {handleopen() {console.log('handleopen');},handleclose() {console.log('handleclose');},handleselect(a, b) {console.log('handleselect');}},mounted() {this.sysName = "I like Kitty";this.logo = require("@/assets/logo.png");} }; </script><style scoped lang="scss"> .menu-bar-container {.el-menu {position:absolute;top: 60px;bottom: 0px;text-align: left;}.logo {position:absolute;top: 0px;height: 60px; line-height: 60px;background: #4b5f6e;img {width: 40px;height: 40px;border-radius: 0px;margin: 10px 10px 10px 10px;float: left;}div {font-size: 22px;color: white;text-align: left;}}.menu-bar-width {width: 200px;}.menu-bar-collapse-width {width: 65px;} } </style>
Main.vue
<template><div class="container"><el-breadcrumb separator="/" class="breadcrumb"><el-breadcrumb-item v-for="item in $route.matched" :key="item.path"><a href="www.baidu.com">{{ item.name }}</a></el-breadcrumb-item></el-breadcrumb><transition name="fade" mode="out-in"><router-view></router-view></transition></div> </template><script> export default {data() {return {};},methods: {},mounted() {} }; </script><style scoped lang="scss"> .container {position: absolute;top: 60px;bottom: 0px;left: 200px;right: 0px;.breadcrumb {padding: 10px; border-color: rgba(38, 86, 114, 0.2);border-bottom-width: 1px;border-bottom-style: solid;background: rgba(138, 158, 170, 0.2);} } </style>
国际化语言切换也被封装成为了组件 LangSelector
LangSelector/index.js
<template><el-dropdown class="lang-selector" @command="handleCommand"><span class="el-dropdown-link"><span id="language">中文</span><i class="el-icon-arrow-down el-icon--right"></i></span><el-dropdown-menu slot="dropdown"><el-dropdown-item command="zh_cn:中文">中文</el-dropdown-item><el-dropdown-item command="en_us:English">English</el-dropdown-item></el-dropdown-menu></el-dropdown> </template><script>export default {methods: {// 语言切换handleCommand(command) {let array = command.split(':')let lang = array[0] === '' ? 'zh_cn' : array[0]let label = array[1]document.getElementById("language").innerHTML = labelthis.$i18n.locale = lang}}} </script>
组件封装重构之后,同步修改路由配置
import Vue from 'vue' import Router from 'vue-router' import Login from '@/views/Login' import NotFound from '@/views/404' import Home from '@/views/Home' import Intro from '@/views/Intro' import User from '@/views/SysMng/User' import Dept from '@/views/SysMng/Dept' import Role from '@/views/SysMng/Role' import Menu from '@/views/SysMng/Menu' import Log from '@/views/SysMng/Log'Vue.use(Router)const router = new Router({routes: [{path: '/',name: '首页',component: Home,children: [{ path: '', component: Intro, name: '系统介绍' },{ path: '/user', component: User, name: '用户管理' },{ path: '/dept', component: Dept, name: '机构管理' },{ path: '/role', component: Role, name: '角色管理' },{ path: '/menu', component: Menu, name: '菜单管理' },{ path: '/log', component: Log, name: '日志管理' }]},{path: '/login',name: '登录',component: Login},{path: '/404',name: 'notFound',component: NotFound}] })router.beforeEach((to, from, next) => {// 登录界面登录成功之后,会把用户信息保存在会话// 存在时间为会话生命周期,页面关闭即失效。let user = sessionStorage.getItem('user');if (to.path == '/login') {// 如果是访问登录界面,如果用户会话信息存在,代表已登录过,跳转到主页if(user) {next({ path: '/' })} else {next()}} else {// 如果访问非登录界面,且户会话信息不存在,代表未登录,则跳转到登录界面if (!user) {next({ path: '/login' })} else {next()}} })export default router
测试效果
封装重构之后,启动界面,效果跟之前差别不大。