參考視頻: VUE項(xiàng)目,VUE項(xiàng)目實(shí)戰(zhàn),vue后臺管理系統(tǒng),前端面試,前端面試項(xiàng)目
案例 | 鏈接 |
---|---|
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-導(dǎo)航欄(視頻p1-16) | https://blog.csdn.net/karshey/article/details/127640658 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-Header+導(dǎo)航欄折疊(p17-19) | https://blog.csdn.net/karshey/article/details/127652862 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-Home組件:卡片、表格(p20-22) | https://blog.csdn.net/karshey/article/details/127674643 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-Echarts圖表準(zhǔn)備:axios封裝、mock數(shù)據(jù)模擬實(shí)戰(zhàn)(p23-25) | https://blog.csdn.net/karshey/article/details/127735159 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-Echarts圖表:折線圖、柱狀圖、餅狀圖(p27-30) | https://blog.csdn.net/karshey/article/details/127737979 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-面包屑、tag欄(p31-35) | https://blog.csdn.net/karshey/article/details/127756733 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-用戶管理:Form表單填寫、Dialog對話框彈出(p36-38) | https://blog.csdn.net/karshey/article/details/127787418 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-用戶管理:Table表格增刪查改、Pagination分頁、搜索框(p39-42) | https://blog.csdn.net/karshey/article/details/127777962 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-登陸頁面Login(p44) | https://blog.csdn.net/karshey/article/details/127795302 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-登陸頁面功能:登錄權(quán)限跳轉(zhuǎn)、路由守衛(wèi)、退出(p45-46) | https://blog.csdn.net/karshey/article/details/127849502 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-登陸不同用戶顯示不同菜單、動態(tài)添加路由(p47-48) | https://blog.csdn.net/karshey/article/details/127865621 |
【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-項(xiàng)目總結(jié) | https://blog.csdn.net/karshey/article/details/127867638 |
目標(biāo)
- 點(diǎn)擊左邊的tab欄,如果在面包屑上沒有則添加
- 點(diǎn)擊面包屑或tag可以進(jìn)行路由跳轉(zhuǎn)
- tag可以刪除
- 若刪除的是當(dāng)前頁面,則路由跳轉(zhuǎn)至下一個tag
- 若刪除的當(dāng)前頁面是最后一個,則跳轉(zhuǎn)至前一個
- 用vuex完成組件間的通信
代碼
0.創(chuàng)建組件、完成路由
首先,我們并沒有Mall、User等組件,我們要先創(chuàng)建它們,然后寫到路由上。至于有哪些路由,見數(shù)據(jù)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,找到對應(yīng)的組件:
<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>
寫進(jìn)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>
我們這里要動態(tài)綁定路由的數(shù)據(jù),點(diǎn)了某個路由才會顯示它。
注意:首頁是不管怎樣都會有的,因此首頁的路由數(shù)據(jù)是寫死在vuex的store的state中的,而其他的是動態(tài)添加的(Array.push)
2.用Vuex完成數(shù)據(jù)的通信:從Aside和Header到面包屑和tag
為什么會有組件間數(shù)據(jù)的通信呢?因?yàn)槲覀凕c(diǎn)擊路由跳轉(zhuǎn)在Aside,顯示的面包屑在Header,而tag在每一個組件都要顯示,所以它要單獨(dú)寫一個組件放進(jìn)Main中。
而組件間的通信我們用的是Vuex,這個在之前用過,具體不再贅述。
在store文件夾下的tab.js添加:
-
tagList
:在state中,用于表示面包屑的數(shù)據(jù) -
selectMenu
:在mutation中,用于更新面包屑的數(shù)據(jù)
export default {
state: {
isCollapse: false,//導(dǎo)航欄是否折疊
tabList: [
{
path: '/',
name: 'home',
label: '首頁',
icon: 's-home',
url: 'Home/Home'
}
],//面包屑的數(shù)據(jù):點(diǎn)了哪個路由,首頁是一定有的
},
mutations: {
// 修改導(dǎo)航欄展開和收起的方法
CollapseMenu(state) {
state.isCollapse = !state.isCollapse
},
// 更新面包屑的數(shù)據(jù)
SelectMenu(state, item) {
// 如果點(diǎn)擊的不在面包屑數(shù)據(jù)中,則添加
const index = state.tabList.findIndex(val => val.name === item.name)
if (index === -1) {
state.tabList.push(item)
}
}
}
}
要在Aside的側(cè)邊欄點(diǎn)擊事件處添加面包屑部分代碼:
clickItem(item) {
// 防止自己跳自己的報錯
if (this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path === '/'))) {
this.$router.push(item.path)
}
// 面包屑
this.$store.commit('SelectMenu',item)
}
到這里,只要在側(cè)邊欄點(diǎn)擊了tab,就會產(chǎn)生路由跳轉(zhuǎn),且點(diǎn)擊的數(shù)據(jù)若是新產(chǎn)生的,則會添加到tagList中。加粗部分是我們上面代碼所完成的需求。
接下來我們需要將tagList中的數(shù)據(jù)在面包屑中顯示出來。在Header的面包屑部分綁定數(shù)據(jù):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
是輔助函數(shù),不了解的話可以去看vuex官方文檔。由于本篇目的只在于做項(xiàng)目,函數(shù)功能不贅述。
import { mapState } from 'vuex'
export default {
computed: {
...mapState({
tags: state => state.tab.tabList
})
}
}
效果:從上到下把所有tab都點(diǎn)一遍。顯然完成了需求,但是樣式不對。
3.面包屑樣式
面包屑樣式需求:
- 和button同一行
- 上下居中
- 和左邊button有距離
- 最后一個的字是白色(#fff)
- 其他顏色的字是灰色(#666)
css:
.l-content {
display: flex;
// 上下居中
align-items: center;
.el-breadcrumb {
margin-left: 15px;
// deep 強(qiáng)制生效
/deep/.el-breadcrumb__item {
.el-breadcrumb__inner {
&.is-link {
color: #666;
}
}
&:last-child {
.el-breadcrumb__inner {
color: #fff;
}
}
}
}
}
效果:
4.tag欄結(jié)構(gòu)
tag欄在任何頁面都要出現(xiàn),說明它要單獨(dú)寫成一個組件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:主題,當(dāng)前主題是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事件
- 刪除:點(diǎn)擊x刪除對應(yīng)的tag和面包屑
- 若刪除的是當(dāng)前頁面,則路由跳轉(zhuǎn)至下一個tag
- 若刪除的當(dāng)前頁面是最后一個,則跳轉(zhuǎn)至前一個
- 點(diǎn)擊:點(diǎn)擊哪個tag就跳轉(zhuǎn)到哪個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>
點(diǎn)擊事件:
changeMenu(item) {
this.$router.push({ name: item.name })
}
刪除事件:
handleClose(item, index) {
// 刪除面包屑數(shù)據(jù)
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中對應(yīng)的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;
// 鼠標(biāo)懸停:小手
cursor: pointer;
}
}
效果
文章來源:http://www.zghlxwxcb.cn/news/detail-697533.html
總代碼
本篇修改或新建的文件
文章來源地址http://www.zghlxwxcb.cn/news/detail-697533.html
CommonTags.vue
<template>
<div class="tabs">
<!-- closable是否可刪除:除了"首頁"都可刪 -->
<!-- effect:主題,當(dāng)前主題是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) {
// 刪除面包屑數(shù)據(jù)
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;
// 鼠標(biāo)懸停:小手
cursor: pointer;
}
}
</style>
tab.js
export default {
state: {
isCollapse: false,//導(dǎo)航欄是否折疊
tabList: [
{
path: '/',
name: 'home',
label: '首頁',
icon: 's-home',
url: 'Home/Home'
}
],//面包屑的數(shù)據(jù):點(diǎn)了哪個路由,首頁是一定有的
},
mutations: {
// 修改導(dǎo)航欄展開和收起的方法
CollapseMenu(state) {
state.isCollapse = !state.isCollapse
},
// 更新面包屑的數(shù)據(jù)
SelectMenu(state, item) {
// 如果點(diǎn)擊的不在面包屑數(shù)據(jù)中,則添加
const index = state.tabList.findIndex(val => val.name === item.name)
if (index === -1) {
state.tabList.push(item)
}
},
// 刪除tag:刪除tabList中對應(yīng)的item
closeTag(state, item) {
// 要刪除的是state.tabList中的item
const index = state.tabList.findIndex(val => val.name === item.name)
state.tabList.splice(index, 1)
}
}
}
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
到了這里,關(guān)于【前端】Vue+Element UI案例:通用后臺管理系統(tǒng)-面包屑、tag欄的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!