组件封装
为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度。
组件结构
组件封装重构后,试图组件结构如下图所示
代码一览
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 = label
this.$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 = label
this.$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
测试效果
封装重构之后,启动界面,效果跟之前差别不大。