基于vuex,keep-alive的多标签页
本人前端实习菜鸡一名,发出的东西都是项目中的一些疑难问题,虽然实现出来了需求,但是代码有些繁琐,希望大佬们多多指教,废话不多说先上图。

先安装vuex
npm
npm install vuex --save
yarn
yarn add vuex --save
新建文件夹用来存放vuex代码

创建index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
loginhash: '',
worktab: {
list: [],
current: {}
},
closingPage: ''
},
mutations: {
loginhash2 (state, hash) {
state.loginhash = hash;
Vue.ls.set('loginhash', hash);
},
biaoqianRemove (state, p) {
const ind = state.worktab.list.findIndex(s => s.key === p.key);
if (ind > -1) {
if (p === state.worktab.current) {
if (state.worktab.list.indexOf(p) === 0) {
state.worktab.list.splice(ind, 1);
if (state.worktab.list.length === 0) {
} else {
history.go(-1);
}
} else {
history.go(-1);
state.worktab.list.splice(ind, 1);
}
} else {
state.worktab.list.splice(ind, 1);
}
}
},
addBiaoqian (state, p) {
const ind = state.worktab.list.findIndex(s => s.key === p.key);
if (ind > -1) {
state.worktab.current = state.worktab.list[ind];
} else {
state.worktab.list.push(p);
state.worktab.current = p;
}
},
addbiaoqian (state, p) {
state.worktab.list = p;
}
},
actions: {
biaoqianRemove ({ commit }, p) {
commit('biaoqianRemove', p);
},
addBiaoqian ({ commit }, p) {
commit('addBiaoqian', p);
},
addbiaoqian ({ commit }, p) {
commit('addbiaoqian', p);
}
}
});
export default store;
在mani.js中import 并挂载
import store from './store';
new Vue({
router,
store: store,
render: h => h(App)
}).$mount('#app');
左侧导航栏(ant Design Vue)
<template>
<div>
<div v-if="ifShow">
<a-menu
mode="inline"
:style="{ height: '100%', borderRight: 0 }"
:defaultOpenKeys="mrdk"
:defaultSelectedKeys="mrxz"
>
<a-sub-menu
v-for="a in yijicaidan"
:key="a.key"
>
<span slot="title">
<a-icon type="a.icon" />{{ a.title }}
</span>
<a-menu-item
v-for="b in a.sub"
:key="b.key"
@click="tiaozhuan(b)"
>
<a-icon type="b.icon" />{{ b.title }}
</a-menu-item>
</a-sub-menu>
</a-menu>
</div>
</div>
</template>
<script>
export default {
name: 'Menu',
data () {
return {
mrxz: [],
mrdk: [],
ifShow: true,
list: [],
yijicaidan: [
{
title: '系统设置',
icon: 'setting',
key: '1',
sub: [
{
title: '首页',
path: '/setting/index',
key: '11',
name: 'index'
},
{ title: '账户设置', path: '/setting/zhanghu', key: '12', name: 'zhanghu' }
]
},
{
title: 'srbac',
icon: 'setting',
key: '2',
sub: [
{
title: 'srbac角色',
path: '/srbac/jueseguanli',
key: '21',
name: 'jueseguanli'
},
{ title: 'srbac资源', path: '/srbac/ziyuanGuanli', key: '22', name: 'ziyuanGuanli' }
]
},
{
title: 'rbac',
icon: 'setting',
key: '3',
sub: [
{
title: 'rbac角色',
path: '/rbac/juese',
key: '31',
name: 'juese'
},
{ title: 'rbac资源', path: '/rbac/ziyuan', key: '32', name: 'ziyuan' }
]
}
]
};
},
methods: {
tiaozhuan (b) {
this.$store.dispatch('addBiaoqian', b);
this.$router.push({ path: b.path });
if (!window.localStorage.biaoqian) {
const c = [];
c.push(b);
window.localStorage.setItem('biaoqian', JSON.stringify(c));
} else {
const a = JSON.parse(window.localStorage.getItem('biaoqian'));
const d = a.findIndex(s => s.key === b.key);
if (d > -1) {
} else {
a.push(b);
window.localStorage.setItem('biaoqian', JSON.stringify(a));
}
}
},
getUrl () {
const url = this.$route.path;
for (const a of this.yijicaidan) {
for (const b of a.sub) {
if (b.path === url) {
this.mrxz.push(b.key);
this.mrdk.push(a.key);
console.log('默认选中数组', this.mrxz);
}
}
}
}
},
mounted () {
this.getUrl();
},
watch: {
$route (to, from) {
console.log(to.fullPath);
for (const a of this.yijicaidan) {
for (const b of a.sub) {
if (b.path === to.fullPath) {
console.log('2222222222222222222222222222222222222222222', to.fullPath);
this.mrxz = [];
this.mrdk = [];
this.mrxz.push(b.key);
this.mrdk.push(a.key);
console.log('监听默认选中', this.mrxz);
this.ifShow = false;
this.$nextTick(() => {
this.ifShow = true;
});
}
}
}
}
}
};
</script>
<style scoped>
</style>
标签页
<template>
<div>
<a-tabs
@change="callback"
type="editable-card"
v-model="activeKey"
@edit="onEdit"
>
<a-tab-pane
v-for="pane in panes"
:tab="pane.title"
:key="pane.key"
>
</a-tab-pane>
</a-tabs>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: 'RouteView',
computed: {
panes () {
return this.$store.state.worktab.list;
},
closingPage () {
return this.$store.state.worktab.closingPage;
}
},
mounted () {
this.getBiaoqian();
this.selBiaoqian();
},
data () {
return {
activeKey: '',
index: 0
};
},
methods: {
getBiaoqian () {
const a = JSON.parse(window.localStorage.getItem('biaoqian'));
this.$store.dispatch('addbiaoqian', a);
},
selBiaoqian () {
console.log(this.$route.path);
const c = this.$route.path;
for (const a of this.$store.state.worktab.list) {
if (a.path === c) {
this.$store.dispatch('addBiaoqian', a);
}
}
},
callback (e) {
const list = this.$store.state.worktab.list;
for (const a of list) {
if (a.key === e) {
this.$router.push({ path: a.path });
}
}
},
onEdit (e) {
for (const a of this.$store.state.worktab.list) {
if (a.key === e) {
this.$store.dispatch('biaoqianRemove', a);
const b = JSON.parse(window.localStorage.getItem('biaoqian'));
for (const c of b) {
if (c.key === e) {
b.splice(this.index, 1);
window.localStorage.setItem('biaoqian', JSON.stringify(b));
this.index = 0;
return;
}
this.index = this.index + 1;
}
}
}
}
},
watch: {
'$store.state.worktab.current' (tab) {
console.log('this.$store.state.worktab.current1', this.$store.state.worktab.current);
if (tab.length === 0) {
this.activeKey = null;
} else {
this.activeKey = tab.key;
}
},
$route (to, from) {
for (const a of this.$store.state.worktab.list) {
if (a.path === to.fullPath) {
this.$store.dispatch('addBiaoqian', a);
}
}
},
'$store.state.worktab.list' (tab) {
console.log('this.$store.state.worktab.list', this.$store.state.worktab.list);
if (tab.length === 0) {
this.$router.push('/');
}
}
}
};
</script>
<style scoped>
</style>
实现原理:基于vuex的数据响应式,点击左侧的导航栏跳转路由并且向index.js中传入标签页的key/title,在标签页中再从index.js中取出标签页需要的key/title来渲染页面,其中刷新保存标签页是widow. storage做的,还有在最后一个页面关闭的时候需要做跳转到指定页面的回调。
还有就是怎样取消keep-alive缓存问题,哪位大佬会麻烦教一下,哈哈哈,查了查没弄明白,我的路由是动态引入的。