组件封装

为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度。

组件结构

组件封装重构后,试图组件结构如下图所示

代码一览

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

测试效果

封装重构之后,启动界面,效果跟之前差别不大。

Vue + Element UI 实现权限管理系统 (功能组件封装)的更多相关文章

  1. Vue + Element UI 实现权限管理系统

    Vue + Element UI 实现权限管理系统 前端篇(一):搭建开发环境 https://www.cnblogs.com/xifengxiaoma/p/9533018.html

  2. Vue + Element UI 实现权限管理系统 前端篇(七):功能组件封装

    组件封装 为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度. 组件结构 组件封装重构后,试图组件结构如下图所示 代码一览 Home组件被简化,包含导航.头部和主内容三个组 ...

  3. Vue + Element UI 实现权限管理系统 前端篇(十三):页面权限控制

    权限控制方案 既然是后台权限管理系统,当然少不了权限控制啦,至于权限控制,前端方面当然就是对页面资源的访问和操作控制啦. 前端资源权限主要又分为两个部分,即导航菜单的查看权限和页面增删改操作按钮的操作 ...

  4. Vue + Element UI 实现权限管理系统 前端篇(十二):用户管理模块

    用户管理模块 添加接口 在 http/moduls/user.js 中添加用户管理相关接口. import axios from '../axios' /* * 用户管理模块 */ // 保存 exp ...

  5. Vue + Element UI 实现权限管理系统 (管理应用状态)

    使用 Vuex 管理应用状态 1. 引入背景 像先前我们是有导航菜单栏收缩和展开功能的,但是因为组件封装的原因,隐藏按钮在头部组件,而导航菜单在导航菜单组件,这样就涉及到了组件收缩状态的共享问题.收缩 ...

  6. Vue + Element UI 实现权限管理系统 前端篇(八):管理应用状态

    使用 Vuex 管理应用状态 1. 引入背景 像先前我们是有导航菜单栏收缩和展开功能的,但是因为组件封装的原因,隐藏按钮在头部组件,而导航菜单在导航菜单组件,这样就涉及到了组件收缩状态的共享问题.收缩 ...

  7. Vue + Element UI 实现权限管理系统 前端篇(十一):第三方图标库

    使用第三方图标库 用过Elment的同鞋都知道,Element UI提供的字体图符少之又少,实在是不够用啊,幸好现在有不少丰富的第三方图标库可用,引入也不会很麻烦. Font Awesome Font ...

  8. Vue + Element UI 实现权限管理系统(第三方图标库)

    使用第三方图标库 用过Elment的同鞋都知道,Element UI提供的字体图符少之又少,实在是不够用啊,幸好现在有不少丰富的第三方图标库可用,引入也不会很麻烦. Font Awesome Font ...

  9. Vue + Element UI 实现权限管理系统 前端篇(十四):菜单功能实现

    菜单功能实现 菜单接口封装 菜单管理是一个对菜单树结构的增删改查操作. 提供一个菜单查询接口,查询整颗菜单树形结构. http/modules/menu.js 添加 findMenuTree 接口. ...

随机推荐

  1. webpack优化记录

    什么是Webpack  .  ( 模块打包机,分析项目结构,找到js不能识别的代码语言,转换和打包后,供browser使用 ) WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到 ...

  2. C#_Demo_摄像头实时_4线程人脸识别注册开发全过程

    v效率有点低,大家看看哪里开可以节省时间?源代码:https://github.com/catzhou2002/ArcFaceDemo说实话,为了提高识别效率,我也是竭尽所能,干了不少自认为的优化,如 ...

  3. rpm命令参数(转载)

    rpm 执行安装包 二进制包(Binary)以及源代码包(Source)两种.二进制包可以直接安装在计算机中,而源代码包将会由RPM自动编译.安装.源代码包经常以src.rpm作为后缀名. 还不清楚具 ...

  4. 通过IP地址定位准确的地理位置

    事情的经过时这样的: 朋友发来一封QQ邮件原文,询问里面显示的IP地址是不是真是的IP地址.然后,我就解锁了一项新技能:通过IP地址定位准确的地理位置 在这里收藏一下这个网址:http://www.8 ...

  5. telnet作用和 命令使用方法详解

    什么是Telnet? 对于Telnet的认识,不同的人持有不同的观点,可以把Telnet当成一种通信协议,但是对于入侵者而言,Telnet只是一种远程登录的工具.一旦入侵者与远程主机建立了Telnet ...

  6. C#打印格式

    一:C#代码直接打印pdf文件(打印质保书pdf文件) 引用: 代码注释很详细了. private void btn_pdf_Click(object sender, RoutedEventArgs ...

  7. English trip V1 - 10.Family Ties 家庭关系 Teacher:Emily Key: Possessive s (所有格 s)

    In this lesson you will learn to talk about people in a family. 课上内容(Lesson) What are you Spring Fes ...

  8. C# 编写WCF简单的服务端与客户端

    http://www.wxzzz.com/1860.html Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Win ...

  9. 20171104xlVBA各人各科进退

    Sub 各班个人各科进步幅度() Dim dRank As Object Set dRank = CreateObject("Scripting.Dictionary") Dim ...

  10. p1470 Longest Prefix

    原本就想到dp,可是是我的思路是在串的各个位置都遍历一次set,看dp[i-st[k]]是否为1且前length(st[k])是st[k].这样200000*200*10会超时.更好的办法是在i位取前 ...