前端转vue
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.vue 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <template>
  2. <div class="ant-pro-multi-tab">
  3. <div class="ant-pro-multi-tab-wrapper">
  4. <a-tabs hideAdd type="editable-card" v-model:activeKey="activeKey"
  5. :tabBarStyle="{ margin: 0, paddingLeft: '11px', paddingTop: '1px' }" @edit="onEdit">
  6. <a-tab-pane v-for="page in pages" :key="page.fullPath" :closable="pages.length > 1" style="height: 0">
  7. <template #tab>
  8. <a-dropdown :trigger="['contextmenu']">
  9. <span :style="{ userSelect: 'none' }">{{ page.meta.customTitle || $t(page.meta.title)
  10. }}</span>
  11. <template #overlay>
  12. <a-menu @click="({ key, item, domEvent }) => {
  13. closeMenuClick(key, page.fullPath);
  14. }">
  15. <a-menu-item key="closeSelf">{{ $t('multiTab.closeCurrent') }}</a-menu-item>
  16. <a-menu-item key="closeRight">{{ $t('multiTab.closeRight') }}</a-menu-item>
  17. <a-menu-item key="closeLeft">{{ $t('multiTab.closeLeft') }}</a-menu-item>
  18. <a-menu-item key="closeAll">{{ $t('multiTab.closeAll') }}</a-menu-item>
  19. </a-menu>
  20. </template>
  21. </a-dropdown>
  22. </template>
  23. </a-tab-pane>
  24. </a-tabs>
  25. </div>
  26. </div>
  27. </template>
  28. <script lang="ts" setup name="MultiTab">
  29. import { ref, reactive, watch, getCurrentInstance } from 'vue'
  30. import { useRouter, RouteLocationNormalizedLoaded } from 'vue-router'
  31. import events from '@/utils/eventBus'
  32. import { message } from 'ant-design-vue'
  33. import { useI18n } from 'vue-i18n'
  34. import './index.less'
  35. let fullPathList: Array<string> = []
  36. const pages = reactive<Array<RouteLocationNormalizedLoaded>>([])
  37. const activeKey = ref('')
  38. const router = useRouter()
  39. const { t } = useI18n()
  40. const { proxy } = getCurrentInstance()
  41. const selectedLastPath = () => {
  42. activeKey.value = fullPathList[fullPathList.length - 1]
  43. }
  44. ; (function created() {
  45. // 全局的事件绑定用于页面内控制tab标签,暂时用不上
  46. // #region
  47. events.once('multiTab.open', (val) => {
  48. if (!val) {
  49. throw new Error(`multi-tab: open tab ${val} err`)
  50. }
  51. activeKey.value = val
  52. })
  53. events.once('multiTab.close', (val) => {
  54. if (!val) {
  55. closeSelf(activeKey.value)
  56. return
  57. }
  58. closeSelf(val)
  59. })
  60. events.once('multiTab.rename', ({ key, name }) => {
  61. console.log('rename', key, name)
  62. try {
  63. const item = pages.find((item) => item.path === key)
  64. item!.meta.customTitle = name
  65. proxy.$forceUpdate()
  66. } catch (e) {
  67. console.error(e)
  68. }
  69. })
  70. // #endregion
  71. pages.push(router.currentRoute.value)
  72. fullPathList.push(router.currentRoute.value.fullPath)
  73. selectedLastPath()
  74. })()
  75. const onEdit = (targetKey, action) => {
  76. //proxy[action](targetKey)
  77. console.log('multiTab onEdit', targetKey, action)
  78. remove(targetKey)
  79. }
  80. const remove = (targetKey) => {
  81. const temp = pages.filter((page) => page.fullPath !== targetKey)
  82. pages.length = 0
  83. pages.push(...temp)
  84. fullPathList = fullPathList.filter((path) => path !== targetKey)
  85. // 判断当前标签是否关闭,若关闭则跳转到最后一个还存在的标签页
  86. if (!fullPathList.includes(activeKey.value)) {
  87. selectedLastPath()
  88. }
  89. }
  90. // content menu
  91. const closeSelf = (e) => {
  92. // 判断是否为最后一个标签页,如果是最后一个,则无法被关闭
  93. if (fullPathList.length > 1) {
  94. remove(e)
  95. } else {
  96. message.info(t('multiTab.cannotCloseLast'))
  97. }
  98. }
  99. const closeLeft = (e) => {
  100. const currentIndex = fullPathList.indexOf(e)
  101. if (currentIndex > 0) {
  102. fullPathList.forEach((item, index) => {
  103. if (index < currentIndex) {
  104. remove(item)
  105. }
  106. })
  107. } else {
  108. message.info(t('multiTab.noLeft'))
  109. }
  110. }
  111. const closeRight = (e) => {
  112. const currentIndex = fullPathList.indexOf(e)
  113. if (currentIndex < fullPathList.length - 1) {
  114. fullPathList.forEach((item, index) => {
  115. if (index > currentIndex) {
  116. remove(item)
  117. }
  118. })
  119. } else {
  120. message.info(t('multiTab.noRight'))
  121. }
  122. }
  123. const closeAll = (e) => {
  124. const currentIndex = fullPathList.indexOf(e)
  125. fullPathList.forEach((item, index) => {
  126. if (index !== currentIndex) {
  127. remove(item)
  128. }
  129. })
  130. }
  131. const closeMenuClick = (key: string, route) => {
  132. console.log('MultiTab-closeMenuClick', key, route)
  133. const allFun = { closeAll, closeRight, closeLeft, closeSelf }
  134. allFun[key](route)
  135. }
  136. watch(
  137. () => router.currentRoute.value,
  138. (newVal) => {
  139. activeKey.value = newVal.fullPath
  140. console.log('MultiTab -newVal', newVal, newVal.fullPath);
  141. console.log('MultiTab -fullPathList', fullPathList);
  142. if (fullPathList.indexOf(newVal.fullPath) < 0) {
  143. fullPathList.push(newVal.fullPath)
  144. pages.push(newVal);
  145. console.log('MultiTab -pages', pages);
  146. }
  147. }
  148. )
  149. watch(activeKey, (newPathKey) => {
  150. console.log('MultiTab -activeKey', activeKey, newPathKey);
  151. router.push({ path: newPathKey })
  152. })
  153. </script>
  154. <style lang="less">
  155. .tab_style() {
  156. .ant-tabs-card {
  157. padding-left: 0;
  158. .ant-tabs-nav-wrap {
  159. margin: 5px
  160. }
  161. .ant-tabs-nav-container {
  162. .ant-tabs-tab-prev:hover,
  163. .ant-tabs-tab-next:hover {
  164. // width: 22px;
  165. background-color: rgba(0, 0, 0, 0.03);
  166. }
  167. height: 37px;
  168. }
  169. .ant-tabs-tab {
  170. height: 32px;
  171. margin-right: 5px;
  172. line-height: 32px;
  173. background: #ffffff;
  174. border: 1px solid #dedede;
  175. }
  176. .ant-tabs-tab-active {
  177. height: 32px;
  178. .anticon-close {
  179. display: inline-block;
  180. }
  181. }
  182. .ant-tabs-tab:hover {
  183. .anticon-close {
  184. color: #333;
  185. display: inline-block;
  186. }
  187. }
  188. }
  189. }
  190. .ant-pro-multi-tab-wrapper {
  191. .tab_style() !important;
  192. }
  193. </style>