大神github项目地址(https://github.com/PanJiaChen/vue-element-admin)
项目中使用大神方案,参考掘金大佬实现方案(https://juejin.im/post/5d9da25e51882576e440937f)
使用vue的vuex与keep-alive将页面信息缓存,实现页面切换时,数据被缓存省去重复加载的过程 中间会新增钩子 activated(激活时触发),deactivated(失活时触发)
TooBar
使用element-UI库,el-tag实现标签显示与关闭功能
通过vuex信息加载路由信息 进行显示,通过关闭按钮清除vuex中的该路由信息
<template>
<div class="toolbar">
<el-tag
class="toolItem"
type="info"
:disable-transitions="false"
:closable="item.id != 0"
effect="plain"
v-for="(item,index) in getToolData" // 循环getToolData 生成标签数据
:key="index"
:class="{active:$route.path == item.detail}" //判断当前路由与getToolData中的数据,路由数据,若相等则,改变class
@click="redirect(item)"
@close="closeToolItem(item)" //method使用见element官方文档
>
<p>{{item.componentName}}</p> //显示标签名
</el-tag>
</div>
</template>
<script>
import { mapGetters } from 'vuex' //引入状态管理器 getter
export default {
methods: {
closeToolItem (item, index) { //点击标签栏的 × 触发方法 作用 1.将标签关闭 2.清除状态管理器的该项路由信息
this.$store.dispatch('clearToolBar', item) //将标签关闭
this.$store.dispatch('clearCache', item.componentName) //清除状态管理器的该项路由信息
},
redirect (item) {
this.$router.push({ path: item.detail }) //点击路由跳转到相应标签对应的路由及页面
}
},
computed: {
...mapGetters(['getToolData', 'getCacheView'])
}
}
</script>
router
keepAlive
用于决定是否被缓存
格式参照如下:
{
name:'哈哈哈',
path: '/data/serviceData',
meta: { title: '服务数据',keepAlive:true },
component: () => import('../views/xxx')
},
{
name:'嘿嘿嘿',
path: '/data/service',
meta: { title: '服务哈哈',keepAlive:false },
component: () => import('../views/xxx')
}
vuex
处理 app.vue与toobar组件传过来的数据
data:{
toolBarData: [], // 保存toobar标签的数组
cacheView: [], // 保存需要缓存的数组
},
actions: {
commitToolBar ({ commit }, data) { //新增路由时,触发 用于新增tab和缓存
commit('setToolData', data)
commit('setCacheView', data)
},
clearToolBar ({ commit }, data) { //关闭指定标签
commit('clearToolItem', data.detail)
},
clearCache ({ commit }, data) { //清除指定路由 从而清缓存
commit('clearCacheView', data)
}
},
mutations:{
setToolData (state, data) {
// 添加标签按钮,如果当前路由已经打开,则不再重复添加
const inToolbar = state.toolBarData.find(item => item.detail === data.detail)
/*
此处可以对新增缓存的路由以及state.toolBarData进行处理
*/
//如果当前路由未打开,则push 新增路由信息
!inToolbar && state.toolBarData.push({
...data
})
},
setCacheView (state, data) { // 与setToolData类似
//如果有则不新增
if (state.cacheView.includes(data.componentName)) return
//else新增
state.cacheView.push(data.componentName)
},
clearToolItem (state, detail) { //
//findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1
const index = state.toolBarData.findIndex(item => item.detail === detail) // 根据需关闭标签的路由path 获取其下标
判断当前页面是否是需要关闭的页面
const isActive = router.app.$route.path === state.toolBarData[index]['detail']
const len = state.toolBarData.length - 1
//从state.toolBarData删除该页面
state.toolBarData.splice(index, 1);
//如果删除页是最后一页 或者是当前显示页 自动跳转到删除后的最后一页 显示出来
(index === len || isActive) && router.push({ path: state.toolBarData[state.toolBarData.length - 1]['detail'] })
},
clearCacheView (state, viewName) {
//从state.cacheView删除路由信息
const index = state.cacheView.findIndex(item => item === viewName)
state.cacheView.splice(index, 1)
},
},
getters:{
getToolData (state) {
return state.toolBarData
},
getCacheView (state) {
return state.cacheView
}
}
入口文件
在vue的入口文件 添加keep-alive
以及路由监听
<template>
...
<el-main style="position:relative;">
<div class="main-container">
<transition name="fade-transform">
<keep-alive :include="cachedViews">
<router-view></router-view>
</keep-alive>
</transition>
</div>
</el-main>
...
</template>
<script>
computed: {
//cachedViews内的被缓存
cachedViews () {
return this.$store.state.cacheView
}
},
method:{
// 此处可以将路由中的信息存储到vuex 根据业务需求 可以自行改写传入参数,内容
setTabs (){
//判断路由meta中是否需要缓存,产生标签
if (this.$route.meta.keepAlive === true) {
const componentName = this.$route.componentName //用于显示
const detail = this.$route.path //此处detail存储路由path
const name = this.$route['name'] //存放路由name
this.$store.dispatch('commitToolBar', { name, detail, componentName})
}
}
},
mounted () {
this.setTabs()
},
watch: {
$route () {
this.setTabs()
}
},
</script>
咳咳 这些差不多就可以实现tab的功能了,样式什么的 :x 可以自己去编写啦
当然 如果页面复用的问题,并且路由信息相同,还想分出两个及以上的标签的话,可以在路由中添加区分的信息,比如判断params的不同,再去dispatch,就可以一个vue页面产生多个标签
效果↓
ps:注意name与组件内的name对应!!!!!!!切记
============================================
请在路由文件下设置以下内容
// 原因 路由跳转的时候两次push的path地址相同
import VueRouter from 'vue-router'
const routerPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
return routerPush.call(this, location).catch(error => error)
}