最近在学习vue,正好手上有个项目还是用jquery写的,就自己尝试将这个项目的前端用vue实现,途中遇到了动态面包屑的问题,特此记录一下,如有不对的地方,欢迎指正.
需求描述:点击左侧的导航,跳转到不同的页面,并且根据导航的路径,动态生成面包屑.面包屑的数据均来自于左侧的导航.
思路:
1.面包屑作为一个单独的组件,在页面中引入.页面的结构如下:
<template>
<div class="page-center">
<top-bar></top-bar> <!--页面顶部信息,固定在顶部-->
<div class="webui-menu-vertical left-nav" v-bind:style="{ width:colspan?'100px':'220px' }">
<menu-vertical
:menu-list="menuList"
@flexMenuClick="flexMenuClick"
@menuClick="menuClick"></menu-vertical>
</div> <!--左侧菜单导航,点击这边的菜单,右边的面包屑变化-->
<div class="right-content" v-bind:style="{ marginLeft: colspan?'100px':'220px' }">
<bread-crumb></bread-crumb> <!--面包屑组件-->
<div class="content">
<router-view></router-view> <!--路由页面-->
</div>
</div>
</div>
</template>
2.面包屑组件的实现:
<!--主要代码实现,样式自己DIY-->
<template>
<div class="bread-crumb">
<ul>
<li v-for=" (item, index) in breadCrumbList" :key="item.title">
<router-link>{{item.title}}</router-link>
<span v-if="index < breadCrumbList.length-1">/</span>
</li>
</ul>
</div>
</template>
<script>
export default {
name:'bread-crumb',
computed: {
breadCrumbList() { //将面包屑的数据存储在vuex状态中
return this.$store.state.breadCrumbList
}
},
}
</script>
3.每次路由更新的时候,更新面包屑的数据:
//main.js
router.beforeEach( (to, from, next) => { //这里用到导航守卫
store.commit('setCurrRouteNme', {currRouteNme:to.name});
store.dispatch('setMenuList').then( ()=> { //因为面包屑的数据来自左侧菜单,这边先获取左侧导航数据然后根据当前路径生成面包屑
store.dispatch('setBreadCrumb');
});
next();
})
//store.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
currRouteNme: String,
oriMenuList:Array,
menuList:Array,
breadCrumbList:Array,
},
mutations: {
setCurrRouteNme( state, payload ) {
state.currRouteNme = payload.currRouteNme
},
setMenuList( state, payload) {
state.menuList = payload.menuList
},
setOriMenuList( state, payload) {
state.oriMenuList = payload.oriMenuList
},
setBreadCrumb( state, payload) {
state.breadCrumbList = payload.breadCrumbList
},
},
actions: { //因为数据是异步请求获取的,所以改变state要通过dispatch,commit只能处理同步数据
setMenuList ( {commit} ) {
let menuList;
return new Promise ( (resolve) => {
axios(url).then( res => { //url是请求菜单数据的接口
menuList = res.data.authList.map(({id,symbol,pId,forward,resName,isLeaf})=>{
return {
id,
symbol,
pId,
forward,
label:resName,
isLeaf:isLeaf,
icon:isLeaf == 1?'':'el-icon-goods'
}
});
commit('setOriMenuList', {
oriMenuList: menuList
});
//这边是为了左侧菜单而进行的数据处理,可忽略
let menuTree = menuList.reduce(function (prev, item) {
prev[item.pId] ? prev[item.pId].push(item) : prev[item.pId] = [item];
return prev;
}, {});
for (let parentItem in menuTree) {
menuTree[parentItem].forEach(function (item) {
item.children = menuTree[item.id] ? menuTree[item.id] : null;
});
}
commit('setMenuList', {
menuList: menuTree[0]
});
resolve();
})
})
},
setBreadCrumb ( {commit, state} ) {
let currMenuList = state.oriMenuList;
let currMenu;
let breadCrumbPre = [];
for (let i=0; i<currMenuList.length; i++) {
if(currMenuList[i]['symbol'] == state.currRouteNme){
currMenu = currMenuList[i];
let breadCrumbItem = {};
breadCrumbItem.title = currMenuList[i].label;
breadCrumbItem.path = '';
breadCrumbPre.unshift(breadCrumbItem);
}
}
function setBreadCrumb(menu){ //递归找出当前菜单的所有父亲菜单
if(menu.pId != 0){
for (let i=0; i<currMenuList.length; i++) {
if(currMenuList[i]['id'] == menu.pId){
let breadCrumbItem = {};
breadCrumbItem.title = currMenuList[i]['label'];
breadCrumbItem.path = '';
breadCrumbPre.unshift(breadCrumbItem);
setBreadCrumb(currMenuList[i])
}
}
}
}
setBreadCrumb(currMenu);
let index = {
title:'首页',
path:''
};
breadCrumbPre.unshift(index);
commit('setBreadCrumb', {
breadCrumbList:breadCrumbPre
})
}
}
})