123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- <template>
- <div class="ant-pro-multi-tab">
- <div class="ant-pro-multi-tab-wrapper">
- <a-tabs hideAdd type="editable-card" v-model:activeKey="activeKey"
- :tabBarStyle="{ margin: 0, paddingLeft: '11px', paddingTop: '1px' }" @edit="onEdit">
- <a-tab-pane v-for="page in pages" :key="page.fullPath" :closable="pages.length > 1" style="height: 0">
- <template #tab>
- <a-dropdown :trigger="['contextmenu']">
- <span :style="{ userSelect: 'none' }">{{ page.meta.customTitle || $t(page.meta.title)
- }}</span>
- <template #overlay>
- <a-menu @click="({ key, item, domEvent }) => {
- closeMenuClick(key, page.fullPath);
- }">
- <a-menu-item key="closeSelf">{{ $t('multiTab.closeCurrent') }}</a-menu-item>
- <a-menu-item key="closeRight">{{ $t('multiTab.closeRight') }}</a-menu-item>
- <a-menu-item key="closeLeft">{{ $t('multiTab.closeLeft') }}</a-menu-item>
- <a-menu-item key="closeAll">{{ $t('multiTab.closeAll') }}</a-menu-item>
- </a-menu>
- </template>
- </a-dropdown>
- </template>
- </a-tab-pane>
- </a-tabs>
- </div>
- </div>
- </template>
- <script lang="ts" setup name="MultiTab">
- import { ref, reactive, watch, getCurrentInstance } from 'vue'
- import { useRouter, RouteLocationNormalizedLoaded } from 'vue-router'
- import events from '@/utils/eventBus'
- import { message } from 'ant-design-vue'
- import { useI18n } from 'vue-i18n'
- import './index.less'
-
- let fullPathList: Array<string> = []
- const pages = reactive<Array<RouteLocationNormalizedLoaded>>([])
- const activeKey = ref('')
- const router = useRouter()
- const { t } = useI18n()
- const { proxy } = getCurrentInstance()
-
- const selectedLastPath = () => {
- activeKey.value = fullPathList[fullPathList.length - 1]
- }
-
- ; (function created() {
- // 全局的事件绑定用于页面内控制tab标签,暂时用不上
- // #region
- events.once('multiTab.open', (val) => {
- if (!val) {
- throw new Error(`multi-tab: open tab ${val} err`)
- }
- activeKey.value = val
- })
- events.once('multiTab.close', (val) => {
- if (!val) {
- closeSelf(activeKey.value)
- return
- }
- closeSelf(val)
- })
- events.once('multiTab.rename', ({ key, name }) => {
- console.log('rename', key, name)
- try {
- const item = pages.find((item) => item.path === key)
- item!.meta.customTitle = name
- proxy.$forceUpdate()
- } catch (e) {
- console.error(e)
- }
- })
- // #endregion
-
- pages.push(router.currentRoute.value)
- fullPathList.push(router.currentRoute.value.fullPath)
- selectedLastPath()
- })()
-
- const onEdit = (targetKey, action) => {
- //proxy[action](targetKey)
- console.log('multiTab onEdit', targetKey, action)
- remove(targetKey)
- }
- const remove = (targetKey) => {
- const temp = pages.filter((page) => page.fullPath !== targetKey)
- pages.length = 0
- pages.push(...temp)
- fullPathList = fullPathList.filter((path) => path !== targetKey)
- // 判断当前标签是否关闭,若关闭则跳转到最后一个还存在的标签页
- if (!fullPathList.includes(activeKey.value)) {
- selectedLastPath()
- }
- }
-
- // content menu
- const closeSelf = (e) => {
- // 判断是否为最后一个标签页,如果是最后一个,则无法被关闭
- if (fullPathList.length > 1) {
- remove(e)
- } else {
- message.info(t('multiTab.cannotCloseLast'))
- }
- }
- const closeLeft = (e) => {
- const currentIndex = fullPathList.indexOf(e)
- if (currentIndex > 0) {
- fullPathList.forEach((item, index) => {
- if (index < currentIndex) {
- remove(item)
- }
- })
- } else {
- message.info(t('multiTab.noLeft'))
- }
- }
- const closeRight = (e) => {
- const currentIndex = fullPathList.indexOf(e)
- if (currentIndex < fullPathList.length - 1) {
- fullPathList.forEach((item, index) => {
- if (index > currentIndex) {
- remove(item)
- }
- })
- } else {
- message.info(t('multiTab.noRight'))
- }
- }
- const closeAll = (e) => {
- const currentIndex = fullPathList.indexOf(e)
- fullPathList.forEach((item, index) => {
- if (index !== currentIndex) {
- remove(item)
- }
- })
- }
- const closeMenuClick = (key: string, route) => {
- console.log('MultiTab-closeMenuClick', key, route)
- const allFun = { closeAll, closeRight, closeLeft, closeSelf }
- allFun[key](route)
- }
-
- watch(
- () => router.currentRoute.value,
- (newVal) => {
- activeKey.value = newVal.fullPath
- console.log('MultiTab -newVal', newVal, newVal.fullPath);
- console.log('MultiTab -fullPathList', fullPathList);
-
-
- if (fullPathList.indexOf(newVal.fullPath) < 0) {
- fullPathList.push(newVal.fullPath)
- pages.push(newVal);
- console.log('MultiTab -pages', pages);
-
- }
- }
- )
-
- watch(activeKey, (newPathKey) => {
- console.log('MultiTab -activeKey', activeKey, newPathKey);
- router.push({ path: newPathKey })
- })
- </script>
- <style lang="less">
- .tab_style() {
- .ant-tabs-card {
- padding-left: 0;
-
- .ant-tabs-nav-wrap {
- margin: 5px
- }
-
- .ant-tabs-nav-container {
-
- .ant-tabs-tab-prev:hover,
- .ant-tabs-tab-next:hover {
- // width: 22px;
- background-color: rgba(0, 0, 0, 0.03);
- }
-
- height: 37px;
- }
-
- .ant-tabs-tab {
- height: 32px;
- margin-right: 5px;
- line-height: 32px;
- background: #ffffff;
- border: 1px solid #dedede;
- }
-
- .ant-tabs-tab-active {
- height: 32px;
-
- .anticon-close {
- display: inline-block;
- }
- }
-
- .ant-tabs-tab:hover {
- .anticon-close {
- color: #333;
- display: inline-block;
- }
- }
- }
- }
-
- .ant-pro-multi-tab-wrapper {
- .tab_style() !important;
- }
- </style>
|