前端Vue+Element UI案例:通用后台管理系统-面包屑tag栏
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端Vue+Element UI案例:通用后台管理系统-面包屑tag栏相关的知识,希望对你有一定的参考价值。
文章目录
目标
- 点击左边的tab栏,如果在面包屑上没有则添加
- 点击面包屑或tag可以进行路由跳转
- tag可以删除
- 若删除的是当前页面,则路由跳转至下一个tag
- 若删除的当前页面是最后一个,则跳转至前一个
- 用vuex完成组件间的通信
代码
0.创建组件、完成路由
首先,我们并没有Mall、User等组件,我们要先创建它们,然后写到路由上。至于有哪些路由,见数据MenuData
:
const MenuData= [
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
,
path: '/mall',
name: 'mall',
label: '商品管理',
icon: 'video-play',
url: 'MallManage/MallManage'
,
path: '/user',
name: 'user',
label: '用户管理',
icon: 'user',
url: 'UserManage/UserManage'
,
label: '其他',
icon: 'location',
children: [
path: '/page1',
name: 'page1',
label: '页面1',
icon: 'setting',
url: 'Other/PageOne'
,
path: '/page2',
name: 'page2',
label: '页面2',
icon: 'setting',
url: 'Other/PageTwo'
]
]
export default MenuData
则router下的index.js如下:
import Vue from "vue";
import VueRouter from "vue-router";
import Main from '../Views/Main'
import Home from '../Views/Home.vue'
import Mall from '../Views/Mall.vue'
import User from '../Views/User.vue'
import PageOne from '../Views/PageOne.vue'
import PageTwo from '../Views/PageTwo.vue'
Vue.use(VueRouter)
const routes=[
// 主路由
path:'/',
component:Main,
redirect: '/home', // 重定向
children:[
// 子路由
// 这是本次写的部分
path: '/home', name: 'home', component: Home , // 首页
path: '/user', name: 'user', component: User , // 用户管理
path: '/mall', name: 'mall', component: Mall , // 商品管理
path: '/page1', name: 'page1', component: PageOne , // 页面1
path: '/page2', name: 'page2', component: PageTwo , // 页面2
]
]
const router = new VueRouter(
routes
)
export default router
1.面包屑
面包屑是放在Header的。我们打开Element UI,找到对应的组件:
<el-breadcrumb separator="/">
<el-breadcrumb-item :to=" path: '/' ">首页</el-breadcrumb-item>
<el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
<el-breadcrumb-item>活动列表</el-breadcrumb-item>
<el-breadcrumb-item>活动详情</el-breadcrumb-item>
</el-breadcrumb>
写进CommonHeader中:
<div class="l-content">
<el-button @click="handleMenu" icon="el-icon-menu" size="mini"></el-button>
<!-- 面包屑 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to=" path: '/' ">首页</el-breadcrumb-item>
</el-breadcrumb>
</div>
我们这里要动态绑定路由的数据,点了某个路由才会显示它。
注意:首页是不管怎样都会有的,因此首页的路由数据是写死在vuex的store的state中的,而其他的是动态添加的(Array.push)
2.用Vuex完成数据的通信:从Aside和Header到面包屑和tag
为什么会有组件间数据的通信呢?因为我们点击路由跳转在Aside,显示的面包屑在Header,而tag在每一个组件都要显示,所以它要单独写一个组件放进Main中。
而组件间的通信我们用的是Vuex,这个在之前用过,具体不再赘述。
在store文件夹下的tab.js添加:
tagList
:在state中,用于表示面包屑的数据selectMenu
:在mutation中,用于更新面包屑的数据
export default
state:
isCollapse: false,//导航栏是否折叠
tabList: [
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
],//面包屑的数据:点了哪个路由,首页是一定有的
,
mutations:
// 修改导航栏展开和收起的方法
CollapseMenu(state)
state.isCollapse = !state.isCollapse
,
// 更新面包屑的数据
SelectMenu(state, item)
// 如果点击的不在面包屑数据中,则添加
const index = state.tabList.findIndex(val => val.name === item.name)
if (index === -1)
state.tabList.push(item)
要在Aside的侧边栏点击事件处添加面包屑部分代码:
clickItem(item)
// 防止自己跳自己的报错
if (this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path === '/')))
this.$router.push(item.path)
// 面包屑
this.$store.commit('SelectMenu',item)
到这里,只要在侧边栏点击了tab,就会产生路由跳转,且点击的数据若是新产生的,则会添加到tagList中。加粗部分是我们上面代码所完成的需求。
接下来我们需要将tagList中的数据在面包屑中显示出来。在Header的面包屑部分绑定数据:v-for对每一个tagList:
<!-- 面包屑 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tags"
:key="item.path"
:to=" path: item.path ">
item.label
</el-breadcrumb-item>
</el-breadcrumb>
js:mapState
是辅助函数,不了解的话可以去看vuex官方文档。由于本篇目的只在于做项目,函数功能不赘述。
import mapState from 'vuex'
export default
computed:
...mapState(
tags: state => state.tab.tabList
)
效果:从上到下把所有tab都点一遍。显然完成了需求,但是样式不对。
3.面包屑样式
面包屑样式需求:
- 和button同一行
- 上下居中
- 和左边button有距离
- 最后一个的字是白色(#fff)
- 其他颜色的字是灰色(#666)
css:
.l-content
display: flex;
// 上下居中
align-items: center;
.el-breadcrumb
margin-left: 15px;
// deep 强制生效
/deep/.el-breadcrumb__item
.el-breadcrumb__inner
&.is-link
color: #666;
&:last-child
.el-breadcrumb__inner
color: #fff;
效果:
4.tag栏结构
tag栏在任何页面都要出现,说明它要单独写成一个组件CommonTags.vue,并放在Main中。
在Element UI中找到tag组件:
稍微看一下script代码,很明显我们用不到它。
<el-tag
v-for="tag in tags"
:key="tag.name"
closable
:type="tag.type">
tag.name
</el-tag>
代码中不了解的属性(Attributes)可以在文档中查一下。红框中为本次会用到的属性:
<template>
<div class="tabs">
<!-- closable是否可删除:除了"首页"都可删 -->
<!-- effect:主题,当前主题是dark,其他事plain -->
<el-tag v-for="item in tags" :key="item.path" :closable="item.name !== 'home'"
:effect="item.name === $route.name ? 'dark' : 'plain'">
item.label
</el-tag>
</div>
</template>
<script>
import mapState from 'vuex'
export default
computed:
...mapState(
tags: state => state.tab.tabList
)
</script>
<style>
</style>
5.tag事件
- 删除:点击x删除对应的tag和面包屑
- 若删除的是当前页面,则路由跳转至下一个tag
- 若删除的当前页面是最后一个,则跳转至前一个
- 点击:点击哪个tag就跳转到哪个tag
这两个事件分别为:(第一万次感叹,组件真好用)
html:
<el-tag v-for="(item, index) in tags" :key="item.path" :closable="item.name !== 'home'"
:effect="item.name === $route.name ? 'dark' : 'plain'" @click="changeMenu(item)"
@close="handleClose(item, index)">
item.label
</el-tag>
点击事件:
changeMenu(item)
this.$router.push( name: item.name )
删除事件:
handleClose(item, index)
// 删除面包屑数据
this.$store.commit('closeTag', item)
// 如果删除的刚好是自己
if (item.name === this.$route.name)
const length = this.tags.length
// 如果删除的是最后一个:跳到前一个
if (length === index)
this.$router.push( name: this.tags[index - 1].name )
// 不是最后一个:往后一个
else
this.$router.push( name: this.tags[index].name )
store中的tab.js,在mutation里:
// 删除tag:删除tabList中对应的item
closeTag(state, item)
// 要删除的是state.tabList中的item
const index = state.tabList.findIndex(val => val.name === item.name)
state.tabList.splice(index, 1)
6.tag样式
.tabs
padding: 20px;
.el-tag
margin-right: 15px;
// 鼠标悬停:小手
cursor: pointer;
效果
总代码
本篇修改或新建的文件
CommonTags.vue
<template>
<div class="tabs">
<!-- closable是否可删除:除了"首页"都可删 -->
<!-- effect:主题,当前主题是dark,其他事plain -->
<el-tag v-for="(item, index) in tags" :key="item.path" :closable="item.name !== 'home'"
:effect="item.name === $route.name ? 'dark' : 'plain'" @click="changeMenu(item)"
@close="handleClose(item, index)">
item.label
</el-tag>
</div>
</template>
<script>
import mapState from 'vuex'
export default
methods:
changeMenu(item)
this.$router.push( name: item.name )
,
handleClose(item, index)
// 删除面包屑数据
this.$store.commit('closeTag', item)
// 如果删除的刚好是自己
if (item.name === this.$route.name)
const length = this.tags.length
// 如果删除的是最后一个:跳到前一个
if (length === index)
this.$router.push( name: this.tags[index - 1].name )
// 不是最后一个:往后一个
else
this.$router.push( name: this.tags[index].name )
,
computed:
...mapState(
tags: state => state.tab.tabList
)
</script>
<style lang="less" scoped>
.tabs
padding: 20px;
.el-tag
margin-right: 15px;
// 鼠标悬停:小手
cursor: pointer;
</style>
tab.js
export default
state:
isCollapse: false,//导航栏是否折叠
tabList: [
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
],//面包屑的数据:点了哪个路由,首页是一定有的
,
mutations:
// 修改导航栏展开和收起的方法
CollapseMenu(state)
state.isCollapse = !state.isCollapse
,
// 更新面包屑的数据
SelectMenu(state, item)
// 如果点击的不在面包屑数据中,则添加
const index = state前端Vue+Element UI案例:通用后台管理系统-项目总结
前端Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单动态添加路由
前端Vue+Element UI案例:通用后台管理系统-导航栏
前端Vue+Element UI案例:通用后台管理系统-Echarts图表:折线图柱状图饼状图