antd vue pro 多页签配置操作,具体操作如下。
1.引入 tagviews文件
在 store/modules 中创建 tagviews.js ,复制一下代码到文件中保存
const state = {
visitedViews: [],
cachedViews: []
}
const mutations = {
ADD_VISITED_VIEW: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return
state.visitedViews.push(
Object.assign({}, view, {
title: view.meta.title || 'no-name'
})
)
},
ADD_CACHED_VIEW: (state, view) => {
if (state.cachedViews.includes(view.name)) return
if (view.meta && view.meta.isCache) {
state.cachedViews.push(view.name)
}
},
DEL_VISITED_VIEW: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
state.visitedViews.splice(i, 1)
break
}
}
},
DEL_CACHED_VIEW: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
index > -1 && state.cachedViews.splice(index, 1)
},
DEL_OTHERS_VISITED_VIEWS: (state, view) => {
state.visitedViews = state.visitedViews.filter(v => {
return v.meta.affix || v.path === view.path
})
},
DEL_OTHERS_CACHED_VIEWS: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
if (index > -1) {
state.cachedViews = state.cachedViews.slice(index, index + 1)
} else {
state.cachedViews = []
}
},
DEL_ALL_VISITED_VIEWS: state => {
// keep affix tags
const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
state.visitedViews = affixTags
},
DEL_ALL_CACHED_VIEWS: state => {
state.cachedViews = []
},
UPDATE_VISITED_VIEW: (state, view) => {
for (let v of state.visitedViews) {
if (v.path === view.path) {
v = Object.assign(v, view)
break
}
}
},
DEL_RIGHT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx <= index || (item.meta && item.meta.affix)) {
return true
}
const i = state.cachedViews.indexOf(item.name)
if (i > -1) {
state.cachedViews.splice(i, 1)
}
return false
})
},
DEL_LEFT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx >= index || (item.meta && item.meta.affix)) {
return true
}
const i = state.cachedViews.indexOf(item.name)
if (i > -1) {
state.cachedViews.splice(i, 1)
}
return false
})
}
}
const actions = {
addView ({
dispatch
}, view) {
dispatch('addVisitedView', view)
dispatch('addCachedView', view)
},
addVisitedView ({
commit
}, view) {
commit('ADD_VISITED_VIEW', view)
},
addCachedView ({
commit
}, view) {
commit('ADD_CACHED_VIEW', view)
},
delView ({
dispatch,
state
}, view) {
return new Promise(resolve => {
dispatch('delVisitedView', view)
dispatch('delCachedView', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delVisitedView ({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_VISITED_VIEW', view)
resolve([...state.visitedViews])
})
},
delCachedView ({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_CACHED_VIEW', view)
resolve([...state.cachedViews])
})
},
delOthersViews ({
dispatch,
state
}, view) {
return new Promise(resolve => {
dispatch('delOthersVisitedViews', view)
dispatch('delOthersCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delOthersVisitedViews ({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_VISITED_VIEWS', view)
resolve([...state.visitedViews])
})
},
delOthersCachedViews ({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_CACHED_VIEWS', view)
resolve([...state.cachedViews])
})
},
delAllViews ({
dispatch,
state
}, view) {
return new Promise(resolve => {
dispatch('delAllVisitedViews', view)
dispatch('delAllCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delAllVisitedViews ({
commit,
state
}) {
return new Promise(resolve => {
commit('DEL_ALL_VISITED_VIEWS')
resolve([...state.visitedViews])
})
},
delAllCachedViews ({
commit,
state
}) {
return new Promise(resolve => {
commit('DEL_ALL_CACHED_VIEWS')
resolve([...state.cachedViews])
})
},
updateVisitedView ({
commit
}, view) {
commit('UPDATE_VISITED_VIEW', view)
},
delRightTags ({
commit
}, view) {
return new Promise(resolve => {
commit('DEL_RIGHT_VIEWS', view)
resolve([...state.visitedViews])
})
},
delLeftTags ({
commit
}, view) {
return new Promise(resolve => {
commit('DEL_LEFT_VIEWS', view)
resolve([...state.visitedViews])
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
2. tagviews文件引用
(1)在 store/getters.js 引入
const getters = {
.....
// 下方两句关键代码
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews
}
export default getters
(2)在 store/index.js 引入
....其他代码
// 关键代码
import tagsView from './modules/tagviews'
.... 其他代码
export default new Vuex.Store({
modules: {
app,
user,
permission,
// 关键代码
tagsView
},
state: {
},
mutations: {
},
actions: {
},
getters
})
3. 更改routeview.vue 文件
在 layouts/RouteView.vue 直接替换成以下代码
<template>
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</template>
<script>
export default {
name: 'RouteView',
computed: {
cachedViews () {
return this.$store.state.tagsView.cachedViews
},
key () {
return this.$route.fullPath
}
},
props: {
keepAlive: {
type: Boolean,
default: true
}
},
data () {
return {}
}
}
</script>
4.更改mutiltable.vue文件
在components/MultiTab/MultiTab.vue 中直接替换以下代码
<script>
import events from './events'
export default {
name: 'MultiTab',
data () {
return {
fullPathList: [],
pages: [],
activeKey: '',
newTabIndex: 0
}
},
created () {
// bind event
events
.$on('open', (val) => {
console.log('table_open', val)
if (!val) {
throw new Error(`multi-tab: open tab ${val} err`)
}
this.activeKey = val
})
.$on('close', (val) => {
if (!val) {
this.closeThat(this.activeKey)
return
}
this.closeThat(val)
})
.$on('rename', ({ key, name }) => {
console.log('rename', key, name)
try {
const item = this.pages.find((item) => item.path === key)
item.meta.customTitle = name
this.$forceUpdate()
} catch (e) {}
})
this.pages.push(this.$route)
this.fullPathList.push(this.$route.fullPath)
this.selectedLastPath()
},
methods: {
onEdit (targetKey, action) {
this[action](targetKey)
},
remove (targetKey) {
const newVal = this.getPage(targetKey)
this.pages = this.pages.filter((page) => page.fullPath !== targetKey)
this.fullPathList = this.fullPathList.filter((path) => path !== targetKey)
if (newVal != null) {
this.$store.dispatch('tagsView/delView', newVal)
}
// 判断当前标签是否关闭,若关闭则跳转到最后一个还存在的标签页
if (!this.fullPathList.includes(this.activeKey)) {
this.selectedLastPath()
}
},
selectedLastPath () {
this.activeKey = this.fullPathList[this.fullPathList.length - 1]
},
getPage (targetKey) {
const newVal = this.pages.filter((c) => c.fullPath === targetKey)
return newVal.length > 0 ? newVal[0] : null
},
// content menu
closeThat (e) {
// 判断是否为最后一个标签页,如果是最后一个,则无法被关闭
if (this.fullPathList.length > 1) {
this.remove(e)
} else {
this.$message.info('这是最后一个标签了, 无法被关闭')
}
},
closeLeft (e) {
const currentIndex = this.fullPathList.indexOf(e)
if (currentIndex > 0) {
this.fullPathList.forEach((item, index) => {
if (index < currentIndex) {
this.remove(item)
}
})
} else {
this.$message.info('左侧没有标签')
}
},
closeRight (e) {
const currentIndex = this.fullPathList.indexOf(e)
if (currentIndex < this.fullPathList.length - 1) {
this.fullPathList.forEach((item, index) => {
if (index > currentIndex) {
this.remove(item)
}
})
} else {
this.$message.info('右侧没有标签')
}
},
closeAll (e) {
const currentIndex = this.fullPathList.indexOf(e)
this.fullPathList.forEach((item, index) => {
if (index !== currentIndex) {
this.remove(item)
}
})
},
refreshPage (e) {
const currentIndex = this.fullPathList.indexOf(e)
this.fullPathList.forEach((item, index) => {
if (index === currentIndex) {
let newVal = this.getPage(item)
if (newVal != null) {
const { path, query, matched } = newVal
matched.forEach((m) => {
if (m.components && m.components.default && m.components.default.name) {
if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
newVal = { name: m.components.default.name, path: path, query: query }
}
}
})
console.log('refreshpage', newVal)
this.$store.dispatch('tagsView/delCachedView', newVal).then((res) => {
const { path, query } = newVal
this.$router.replace({
path: '/redirect' + path,
query: query
})
})
}
}
})
},
closeMenuClick (key, route) {
this[key](route)
},
renderTabPaneMenu (e) {
return (
<a-menu
{...{
on: {
click: ({ key, item, domEvent }) => {
this.closeMenuClick(key, e)
}
}
}}
>
<a-menu-item key="closeThat">关闭当前标签</a-menu-item>
<a-menu-item key="closeRight">关闭右侧</a-menu-item>
<a-menu-item key="closeLeft">关闭左侧</a-menu-item>
<a-menu-item key="closeAll">关闭全部</a-menu-item>
<a-menu-item key="refreshPage">刷新标签</a-menu-item>
</a-menu>
)
},
// render
renderTabPane (title, keyPath) {
const menu = this.renderTabPaneMenu(keyPath)
return (
<a-dropdown overlay={menu} trigger={['contextmenu']}>
<span style={{ userSelect: 'none' }}>{title}</span>
</a-dropdown>
)
},
addtags () {
const newVal = this.$route
this.$store.dispatch('tagsView/addView', newVal)
}
},
mounted () {
this.addtags()
},
watch: {
$route: function (newVal) {
this.activeKey = newVal.fullPath
this.addtags()
if (this.fullPathList.indexOf(newVal.fullPath) < 0) {
this.fullPathList.push(newVal.fullPath)
this.pages.push(newVal)
}
},
activeKey: function (newPathKey) {
this.$router.push({ path: newPathKey })
}
},
render () {
const {
onEdit,
$data: { pages }
} = this
const panes = pages.map((page) => {
return (
<a-tab-pane
style={{ height: 0 }}
tab={this.renderTabPane(page.meta.customTitle || page.meta.title, page.fullPath)}
key={page.fullPath}
closable={pages.length > 1}
></a-tab-pane>
)
})
return (
<div class="ant-pro-multi-tab">
<div class="ant-pro-multi-tab-wrapper">
<a-tabs
hideAdd
type={'editable-card'}
v-model={this.activeKey}
tabBarStyle={{ background: '#FFF', margin: 0, paddingLeft: '16px', paddingTop: '1px' }}
{...{ on: { edit: onEdit } }}
>
{panes}
</a-tabs>
</div>
</div>
)
}
}
</script>
5.生成路由地方配置,本文路由生成在 permission.js中,具体位置看项目
注意事项:
1、每个路由的name必须跟页面内的name一致,否则不会缓存
2、路由当中的isCache 是控制多页签是否缓存重要属性(可自己控制是否缓存开关)
至此流程结束,多页签功能完成