mirror of
https://github.com/iczer/vue-antd-admin
synced 2025-04-05 19:41:37 +08:00
parent
83576d88d7
commit
313af63f33
@ -33,6 +33,7 @@ export default {
|
|||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
target: null,
|
target: null,
|
||||||
|
meta: null,
|
||||||
selectedKeys: []
|
selectedKeys: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -45,14 +46,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
const clickHandler = () => this.closeMenu()
|
window.addEventListener('click', this.closeMenu)
|
||||||
const contextMenuHandler = e => this.setPosition(e)
|
window.addEventListener('contextmenu', this.setPosition)
|
||||||
window.addEventListener('click', clickHandler)
|
},
|
||||||
window.addEventListener('contextmenu', contextMenuHandler)
|
beforeDestroy() {
|
||||||
this.$emit('hook:beforeDestroy', () => {
|
window.removeEventListener('click', this.closeMenu)
|
||||||
window.removeEventListener('click', clickHandler)
|
window.removeEventListener('contextmenu', this.setPosition)
|
||||||
window.removeEventListener('contextmenu', contextMenuHandler)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeMenu () {
|
closeMenu () {
|
||||||
@ -62,9 +61,10 @@ export default {
|
|||||||
this.left = e.clientX
|
this.left = e.clientX
|
||||||
this.top = e.clientY
|
this.top = e.clientY
|
||||||
this.target = e.target
|
this.target = e.target
|
||||||
|
this.meta = e.meta
|
||||||
},
|
},
|
||||||
handleClick ({ key }) {
|
handleClick ({ key }) {
|
||||||
this.$emit('select', key, this.target)
|
this.$emit('select', key, this.target, this.meta)
|
||||||
this.closeMenu()
|
this.closeMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
:class="['tabs-container', layout, pageWidth, {'affixed' : affixed, 'fixed-header' : fixedHeader, 'collapsed' : adminLayout.collapsed}]"
|
:class="['tabs-container', layout, pageWidth, {'affixed' : affixed, 'fixed-header' : fixedHeader, 'collapsed' : adminLayout.collapsed}]"
|
||||||
:active-key="active"
|
:active-key="active"
|
||||||
:hide-add="true"
|
:hide-add="true"
|
||||||
@change="onChange"
|
|
||||||
@edit="onEdit"
|
|
||||||
@contextmenu="onContextmenu"
|
|
||||||
>
|
>
|
||||||
<a-tooltip placement="left" :title="lockTitle" slot="tabBarExtraContent">
|
<a-tooltip placement="left" :title="lockTitle" slot="tabBarExtraContent">
|
||||||
<a-icon
|
<a-icon
|
||||||
@ -18,7 +15,11 @@
|
|||||||
/>
|
/>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tab-pane v-for="page in pageList" :key="page.fullPath">
|
<a-tab-pane v-for="page in pageList" :key="page.fullPath">
|
||||||
<span slot="tab" :pagekey="page.fullPath">{{pageName(page)}}</span>
|
<div slot="tab" class="tab" @contextmenu="e => onContextmenu(page.fullPath, e)">
|
||||||
|
<a-icon v-if="page.fullPath === active || page.loading" @click="onRefresh(page)" class="icon-sync" :type="page.loading ? 'loading' : 'sync'" />
|
||||||
|
<span @click="onTabClick(page.fullPath)" >{{pageName(page)}}</span>
|
||||||
|
<a-icon @click="onClose(page.fullPath)" class="icon-close" type="close"/>
|
||||||
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<div v-if="affixed" class="virtual-tabs"></div>
|
<div v-if="affixed" class="virtual-tabs"></div>
|
||||||
@ -58,11 +59,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
inject:['adminLayout'],
|
inject:['adminLayout'],
|
||||||
watch: {
|
|
||||||
'adminLayout.collapsed': (val) => {
|
|
||||||
console.log(val)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
created() {
|
||||||
this.affixed = this.fixedTabs
|
this.affixed = this.fixedTabs
|
||||||
},
|
},
|
||||||
@ -84,16 +80,19 @@
|
|||||||
this.affixed = false
|
this.affixed = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChange(key) {
|
onTabClick(key) {
|
||||||
this.$emit('change', key)
|
if (this.active !== key) {
|
||||||
},
|
this.$emit('change', key)
|
||||||
onEdit(key, action) {
|
|
||||||
if (action === 'remove') {
|
|
||||||
this.$emit('close', key)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onContextmenu(e) {
|
onClose(key) {
|
||||||
this.$emit('contextmenu', e)
|
this.$emit('close', key)
|
||||||
|
},
|
||||||
|
onRefresh(page) {
|
||||||
|
this.$emit('refresh', page.fullPath, page)
|
||||||
|
},
|
||||||
|
onContextmenu(pageKey, e) {
|
||||||
|
this.$emit('contextmenu', pageKey, e)
|
||||||
},
|
},
|
||||||
pageName(page) {
|
pageName(page) {
|
||||||
return this.$t(getI18nKey(page.keyPath))
|
return this.$t(getI18nKey(page.keyPath))
|
||||||
@ -103,6 +102,28 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.tab{
|
||||||
|
margin: 0 -16px;
|
||||||
|
padding: 0 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
user-select: none;
|
||||||
|
.icon-close{
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 6px;
|
||||||
|
margin-right: -4px;
|
||||||
|
color: @text-color-second;
|
||||||
|
&:hover{
|
||||||
|
color: @text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon-sync{
|
||||||
|
margin-left: -4px;
|
||||||
|
color: @primary-4;
|
||||||
|
&:hover{
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.tabs-head{
|
.tabs-head{
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
&.head.fixed{
|
&.head.fixed{
|
||||||
|
@ -7,12 +7,13 @@
|
|||||||
:page-list="pageList"
|
:page-list="pageList"
|
||||||
@change="changePage"
|
@change="changePage"
|
||||||
@close="remove"
|
@close="remove"
|
||||||
|
@refresh="refresh"
|
||||||
@contextmenu="onContextmenu"
|
@contextmenu="onContextmenu"
|
||||||
/>
|
/>
|
||||||
<div :class="['tabs-view-content', layout, pageWidth]" :style="`margin-top: ${multiPage ? -24 : 0}px`">
|
<div :class="['tabs-view-content', layout, pageWidth]" :style="`margin-top: ${multiPage ? -24 : 0}px`">
|
||||||
<page-toggle-transition :disabled="animate.disabled" :animate="animate.name" :direction="animate.direction">
|
<page-toggle-transition :disabled="animate.disabled" :animate="animate.name" :direction="animate.direction">
|
||||||
<a-keep-alive v-if="multiPage" v-model="clearCaches">
|
<a-keep-alive v-if="multiPage" v-model="clearCaches">
|
||||||
<router-view ref="tabContent" :key="$route.fullPath" />
|
<router-view v-if="!refreshing" ref="tabContent" :key="$route.fullPath" />
|
||||||
</a-keep-alive>
|
</a-keep-alive>
|
||||||
<router-view v-else />
|
<router-view v-else />
|
||||||
</page-toggle-transition>
|
</page-toggle-transition>
|
||||||
@ -38,7 +39,8 @@ export default {
|
|||||||
clearCaches: [],
|
clearCaches: [],
|
||||||
pageList: [],
|
pageList: [],
|
||||||
activePage: '',
|
activePage: '',
|
||||||
menuVisible: false
|
menuVisible: false,
|
||||||
|
refreshing: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -47,7 +49,8 @@ export default {
|
|||||||
return [
|
return [
|
||||||
{ key: '1', icon: 'vertical-right', text: this.$t('closeLeft') },
|
{ key: '1', icon: 'vertical-right', text: this.$t('closeLeft') },
|
||||||
{ key: '2', icon: 'vertical-left', text: this.$t('closeRight') },
|
{ key: '2', icon: 'vertical-left', text: this.$t('closeRight') },
|
||||||
{ key: '3', icon: 'close', text: this.$t('closeOthers') }
|
{ key: '3', icon: 'close', text: this.$t('closeOthers') },
|
||||||
|
{ key: '4', icon: 'sync', text: this.$t('refresh') },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
tabsOffset() {
|
tabsOffset() {
|
||||||
@ -106,9 +109,6 @@ export default {
|
|||||||
this.activePage = key
|
this.activePage = key
|
||||||
this.$router.push(key)
|
this.$router.push(key)
|
||||||
},
|
},
|
||||||
editPage (key, action) {
|
|
||||||
this[action](key) // remove
|
|
||||||
},
|
|
||||||
remove (key, next) {
|
remove (key, next) {
|
||||||
if (this.pageList.length === 1) {
|
if (this.pageList.length === 1) {
|
||||||
return this.$message.warning(this.$t('warn'))
|
return this.$message.warning(this.$t('warn'))
|
||||||
@ -124,19 +124,30 @@ export default {
|
|||||||
this.$router.push(this.activePage)
|
this.$router.push(this.activePage)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onContextmenu (e) {
|
refresh (key, page) {
|
||||||
const pageKey = getPageKey(e.target)
|
page = page || this.pageList.find(item => item.fullPath === key)
|
||||||
|
page.loading = true
|
||||||
|
this.clearCache(page)
|
||||||
|
if (key === this.activePage) {
|
||||||
|
this.reloadContent(() => page.loading = false)
|
||||||
|
} else {
|
||||||
|
// 其实刷新很快,加这个延迟纯粹为了 loading 状态多展示一会儿,让用户感知刷新这一过程
|
||||||
|
setTimeout(() => page.loading = false, 500)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onContextmenu(pageKey, e) {
|
||||||
if (pageKey) {
|
if (pageKey) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
e.meta = pageKey
|
||||||
this.menuVisible = true
|
this.menuVisible = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMenuSelect (key, target) {
|
onMenuSelect (key, target, pageKey) {
|
||||||
let pageKey = getPageKey(target)
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case '1': this.closeLeft(pageKey); break
|
case '1': this.closeLeft(pageKey); break
|
||||||
case '2': this.closeRight(pageKey); break
|
case '2': this.closeRight(pageKey); break
|
||||||
case '3': this.closeOthers(pageKey); break
|
case '3': this.closeOthers(pageKey); break
|
||||||
|
case '4': this.refresh(pageKey); break
|
||||||
default: break
|
default: break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -172,6 +183,22 @@ export default {
|
|||||||
this.$router.push(this.activePage)
|
this.$router.push(this.activePage)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
clearCache(page) {
|
||||||
|
page._init_ = false
|
||||||
|
this.clearCaches = [page.cachedKey]
|
||||||
|
},
|
||||||
|
reloadContent(onLoaded) {
|
||||||
|
this.refreshing = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.refreshing = false
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.setCachedKey(this.$route)
|
||||||
|
if (typeof onLoaded === 'function') {
|
||||||
|
onLoaded.apply(this, [])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
pageName(page) {
|
pageName(page) {
|
||||||
return this.$t(getI18nKey(page.keyPath))
|
return this.$t(getI18nKey(page.keyPath))
|
||||||
},
|
},
|
||||||
@ -180,6 +207,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
addListener() {
|
addListener() {
|
||||||
window.addEventListener('page:close', this.closePageListener)
|
window.addEventListener('page:close', this.closePageListener)
|
||||||
|
window.addEventListener('page:refresh', this.refreshPageListener)
|
||||||
window.addEventListener('unload', this.unloadListener)
|
window.addEventListener('unload', this.unloadListener)
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -187,6 +215,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
removeListener() {
|
removeListener() {
|
||||||
window.removeEventListener('page:close', this.closePageListener)
|
window.removeEventListener('page:close', this.closePageListener)
|
||||||
|
window.removeEventListener('page:refresh', this.refreshPageListener)
|
||||||
window.removeEventListener('unload', this.unloadListener)
|
window.removeEventListener('unload', this.unloadListener)
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -198,6 +227,14 @@ export default {
|
|||||||
const closePath = typeof closeRoute === 'string' ? closeRoute : closeRoute.path
|
const closePath = typeof closeRoute === 'string' ? closeRoute : closeRoute.path
|
||||||
this.remove(closePath, nextRoute)
|
this.remove(closePath, nextRoute)
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 页面刷新事件监听
|
||||||
|
* @param event 页签关闭事件
|
||||||
|
*/
|
||||||
|
refreshPageListener(event) {
|
||||||
|
const {pageKey} = event.detail
|
||||||
|
this.refresh(pageKey)
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 页面 unload 事件监听器,添加页签到 session 缓存,用于刷新时保留页签
|
* 页面 unload 事件监听器,添加页签到 session 缓存,用于刷新时保留页签
|
||||||
*/
|
*/
|
||||||
@ -206,7 +243,7 @@ export default {
|
|||||||
sessionStorage.setItem(process.env.VUE_APP_TBAS_KEY, JSON.stringify(tabs))
|
sessionStorage.setItem(process.env.VUE_APP_TBAS_KEY, JSON.stringify(tabs))
|
||||||
},
|
},
|
||||||
createPage(route) {
|
createPage(route) {
|
||||||
return {keyPath: route.matched[route.matched.length - 1].path, fullPath: route.fullPath}
|
return {keyPath: route.matched[route.matched.length - 1].path, fullPath: route.fullPath, loading: false}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 设置页面缓存的key
|
* 设置页面缓存的key
|
||||||
@ -240,20 +277,6 @@ export default {
|
|||||||
...mapMutations('setting', ['correctPageMinHeight'])
|
...mapMutations('setting', ['correctPageMinHeight'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 由于ant-design-vue组件库的TabPane组件暂不支持自定义监听器,无法直接获取到右键target所在标签页的 pagekey 。故增加此方法用于
|
|
||||||
* 查询右键target所在标签页的标识 pagekey ,以用于自定义右键菜单的事件处理。
|
|
||||||
* 注:TabPane组件支持自定义监听器后可去除该方法并重构 ‘自定义右键菜单的事件处理’
|
|
||||||
* @param target 查询开始目标
|
|
||||||
* @param depth 查询层级深度 (查找层级最多不超过3层,超过3层深度直接返回 null)
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
function getPageKey (target, depth = 0) {
|
|
||||||
if (depth > 2 || !target) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return target.getAttribute('pagekey') || getPageKey(target.firstElementChild, ++depth)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
@ -4,18 +4,21 @@ module.exports = {
|
|||||||
closeLeft: '关闭左侧',
|
closeLeft: '关闭左侧',
|
||||||
closeRight: '关闭右侧',
|
closeRight: '关闭右侧',
|
||||||
closeOthers: '关闭其它',
|
closeOthers: '关闭其它',
|
||||||
|
refresh: '刷新页面',
|
||||||
warn: '这是最后一页,不能再关闭了',
|
warn: '这是最后一页,不能再关闭了',
|
||||||
},
|
},
|
||||||
HK: {
|
HK: {
|
||||||
closeLeft: '關閉左側',
|
closeLeft: '關閉左側',
|
||||||
closeRight: '關閉右側',
|
closeRight: '關閉右側',
|
||||||
closeOthers: '關閉其它',
|
closeOthers: '關閉其它',
|
||||||
|
refresh: '刷新頁面',
|
||||||
warn: '這是最後一頁,不能再關閉了',
|
warn: '這是最後一頁,不能再關閉了',
|
||||||
},
|
},
|
||||||
US: {
|
US: {
|
||||||
closeLeft: 'close left',
|
closeLeft: 'close left',
|
||||||
closeRight: 'close right',
|
closeRight: 'close right',
|
||||||
closeOthers: 'close others',
|
closeOthers: 'close others',
|
||||||
|
refresh: 'refresh the page',
|
||||||
warn: 'This is the last page, you can\'t close it',
|
warn: 'This is the last page, you can\'t close it',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@ const TabsPagePlugin = {
|
|||||||
$closePage(closeRoute, nextRoute) {
|
$closePage(closeRoute, nextRoute) {
|
||||||
const event = new CustomEvent('page:close', {detail:{closeRoute, nextRoute}})
|
const event = new CustomEvent('page:close', {detail:{closeRoute, nextRoute}})
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event)
|
||||||
|
},
|
||||||
|
$refreshPage(pageKey) {
|
||||||
|
const event = new CustomEvent('page:refresh', {detail:{pageKey}})
|
||||||
|
window.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user