本文是基于 permission-control 分支 模板添加 TagsView。


  • 拷贝文件

vue-element-admin 中复制以下文件:

1
2
3
/src/layout/components/TagsView
/src/store/modules/tagsView.js
/src/views/redirect

  • 修改 src/layout/components/AppMain.vue 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<template>
<section class="app-main">
<transition
name="fade-transform"
mode="out-in"
>
<!-- 1. 注释 -->
<!-- <router-view :key="key" /> -->
<!-- 2. 新增 -->
<keep-alive :include="cachedViews">
<router-view></router-view>
</keep-alive>
</transition>
</section>
</template>

<script>
export default {
name: 'AppMain',
computed: {
key() {
return this.$route.path
},
// 3. 新增
cachedViews() {
return this.$store.state.tagsView.cachedViews
}
}
}
</script>

<style lang="scss" scoped>
.app-main {
/*50 = navbar */
min-height: calc(100vh - 50px);
width: 100%;
position: relative;
overflow: hidden;
}
.fixed-header + .app-main {
padding-top: 50px;
}

// 4. 新增
.hasTagsView {
.app-main {
/* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px);
}

.fixed-header + .app-main {
padding-top: 84px;
}
}
</style>

<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
.fixed-header {
padding-right: 15px;
}
}
</style>

  • 修改 src/layout/components/index.js 文件
1
2
3
4
export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar'
export { default as AppMain } from './AppMain'
export { default as TagsView } from './TagsView' // 新增

  • 修改 src/layout/index.vue 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<template>
<div
:class="classObj"
class="app-wrapper"
>
<div
v-if="device==='mobile'&&sidebar.opened"
class="drawer-bg"
@click="handleClickOutside"
/>
<sidebar class="sidebar-container" />
<!-- 1. 将 class 为 main-container 的标签替换如下 -->
<div
:class="{hasTagsView:needTagsView}"
class="main-container"
>
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
</div>
</div>
</template>

<script>
// 2. 新增 TagsView
import { Navbar, Sidebar, AppMain, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'

export default {
name: 'Layout',
components: {
Navbar,
Sidebar,
AppMain,
TagsView // 3. 新增
},
mixins: [ResizeMixin],
computed: {
sidebar() {
return this.$store.state.app.sidebar
},
device() {
return this.$store.state.app.device
},
fixedHeader() {
return this.$store.state.settings.fixedHeader
},
// 4. 新增
needTagsView() {
return this.$store.state.settings.tagsView
},
classObj() {
return {
hideSidebar: !this.sidebar.opened,
openSidebar: this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
}
}
</script>

<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";

.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar {
position: fixed;
top: 0;
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}

.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$sideBarWidth});
transition: width 0.28s;
}

.hideSidebar .fixed-header {
width: calc(100% - 54px);
}

.mobile .fixed-header {
width: 100%;
}
</style>

  • 修改 src/store/getters.js 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
roles: state => state.user.roles,
permission_routes: state => state.permission.routes,

// 新增
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
}
export default getters

  • 修改 src/store/index.js 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import app from './modules/app'
import permission from './modules/permission'
import settings from './modules/settings'
import user from './modules/user'

// 1. 新增
import tagsView from './modules/tagsView'

Vue.use(Vuex)

const store = new Vuex.Store({
modules: {
app,
permission,
settings,
user,
tagsView // 2. 新增
},
getters
})

export default store

  • 修改 src/store/modules/settings.js 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import defaultSettings from '@/settings'

// 1. 新增 tagsView
const { showSettings, fixedHeader, sidebarLogo, tagsView } = defaultSettings

const state = {
showSettings: showSettings,
fixedHeader: fixedHeader,
sidebarLogo: sidebarLogo,
// 2. 新增
tagsView: tagsView,
}

const mutations = {
CHANGE_SETTING: (state, { key, value }) => {
// eslint-disable-next-line no-prototype-builtins
if (state.hasOwnProperty(key)) {
state[key] = value
}
}
}

const actions = {
changeSetting({ commit }, data) {
commit('CHANGE_SETTING', data)
}
}

export default {
namespaced: true,
state,
mutations,
actions
}

  • 修改 src/settings.js 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {

title: 'Vue Admin Template',

/**
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: true,

/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: true,

/**
* @type {boolean} true | false
* @description 是否显示 tagsView
*/
tagsView: true
}

  • 修改 src/router/index.js 文件

添加此路由:

1
2
3
4
5
6
7
8
9
10
11
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path*',
component: () => import('@/views/redirect/index')
}
]
},

修改后的详细代码 - LqZww