组件封装

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

组件结构

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

代码一览

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. vue双向绑定(数据劫持+发布者-订阅者模式)

    参考文献:https://www.cnblogs.com/libin-1/p/6893712.html 实现mvvm主要包含两个方面,数据变化更新视图,视图变化更新数据. 关键点在于data如何更新v ...

  2. 《剑指offer》第五十三题(0到n-1中缺失的数字)

    // 面试题53(二):0到n-1中缺失的数字 // 题目:一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字 // 都在范围0到n-1之内.在范围0到n-1的n个数字中有且只有一个数 ...

  3. include

    1. 自己写的文件都用:include "....." 2. 如果A类include了B,那么在主函数中,只用include A类,就可以使用B类了,但是此时不能再include ...

  4. Qt5标准文件对话框类

    getOpenFileName()函数返回用户选择的文件名,其函数形式如下: QString QFileDialog::getOpenFileName(QWidget *parent = Q_NULL ...

  5. 温馨小程序前端布局Flex

    伸缩容器支持的属性有: 1,display 2,flex-direction 3,flex-wrap 4,flex-flow 5,justify-content 6,align-items 7,ali ...

  6. Python Selenium 文件上传之Autoit

    今天补充一种文件上传的方法 主要是因为工作中使用SendKeys方法不稳定,具体方法见: Python Selenium 文件上传之SendKeys 这种方法直接通过命令行执行脚本时没有问题,可以成功 ...

  7. dataway_代码规范

    无论何时无论何地,只要写代码,请遵从这样的规范. ----------------------------------------------------------------- css代码规范. ...

  8. RabbitMQ消费方式汇总

    在学习本章节前,请先学习之前的章节:Java访问RabbitMQ:https://www.cnblogs.com/duanjt/p/10057330.htmlRabbitMQ消息发布时的权衡:http ...

  9. gooreplacer 很好用

    国内上 StackOverflow, hackernews 之类的站点会慢. 因为页面里有链接指向 google 谷歌, 会被墙. 于是拖累了整个页面的显示. gooreplacer 可以把这些被墙连 ...

  10. JS过渡和变形效果演示(举例:鼠标滑过图片放大) --JS案例

    1.代码: <!DOCTYPE html><html><head> <meta charset="utf-8"> <title ...