MultiTab.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <!--
  2. <template>
  3. <div style="margin: -23px -24px 24px -24px">
  4. &lt;!&ndash;<a-dropdown :trigger="['contextmenu']" overlayClassName="multi-tab-menu-wrapper">
  5. <a-menu slot="overlay">
  6. <a-menu-item key="1">1st menu item</a-menu-item>
  7. <a-menu-item key="2">2nd menu item</a-menu-item>
  8. <a-menu-item key="3">3rd menu item</a-menu-item>
  9. </a-menu>
  10. </a-dropdown>&ndash;&gt;
  11. <a-tabs
  12. hideAdd
  13. v-model="activeKey"
  14. type="editable-card"
  15. :tabBarStyle="{ background: '#FFF', margin: 0, paddingLeft: '16px', paddingTop: '1px' }"
  16. @edit="onEdit"
  17. >
  18. <a-tab-pane v-for="page in pages" :style="{ height: 0 }" :tab="page.meta.title" :key="page.fullPath" :closable="pages.length > 1">
  19. </a-tab-pane>
  20. <template slot="renderTabBar" slot-scope="props, DefaultTabBar">
  21. <component :is="DefaultTabBar" {...props} />
  22. </template>
  23. </a-tabs>
  24. </div>
  25. </template>
  26. -->
  27. <script>
  28. export default {
  29. name: 'MultiTab',
  30. data () {
  31. return {
  32. fullPathList: [],
  33. pages: [],
  34. activeKey: '',
  35. newTabIndex: 0
  36. }
  37. },
  38. created () {
  39. this.pages.push(this.$route)
  40. this.fullPathList.push(this.$route.fullPath)
  41. this.selectedLastPath()
  42. },
  43. methods: {
  44. onEdit (targetKey, action) {
  45. this[action](targetKey)
  46. },
  47. remove (targetKey) {
  48. this.pages = this.pages.filter(page => page.fullPath !== targetKey)
  49. this.fullPathList = this.fullPathList.filter(path => path !== targetKey)
  50. // 判断当前标签是否关闭,若关闭则跳转到最后一个还存在的标签页
  51. if (!this.fullPathList.includes(this.activeKey)) {
  52. this.selectedLastPath()
  53. }
  54. },
  55. selectedLastPath () {
  56. this.activeKey = this.fullPathList[this.fullPathList.length - 1]
  57. },
  58. // content menu
  59. closeThat (e) {
  60. this.remove(e)
  61. },
  62. closeLeft (e) {
  63. const currentIndex = this.fullPathList.indexOf(e)
  64. if (currentIndex > 0) {
  65. this.fullPathList.forEach((item, index) => {
  66. if (index < currentIndex) {
  67. this.remove(item)
  68. }
  69. })
  70. } else {
  71. this.$message.info('左侧没有标签')
  72. }
  73. },
  74. closeRight (e) {
  75. const currentIndex = this.fullPathList.indexOf(e)
  76. if (currentIndex < (this.fullPathList.length - 1)) {
  77. this.fullPathList.forEach((item, index) => {
  78. if (index > currentIndex) {
  79. this.remove(item)
  80. }
  81. })
  82. } else {
  83. this.$message.info('右侧没有标签')
  84. }
  85. },
  86. closeAll (e) {
  87. const currentIndex = this.fullPathList.indexOf(e)
  88. this.fullPathList.forEach((item, index) => {
  89. if (index !== currentIndex) {
  90. this.remove(item)
  91. }
  92. })
  93. },
  94. closeMenuClick ({ key, item, domEvent }) {
  95. const vkey = domEvent.target.getAttribute('data-vkey')
  96. switch (key) {
  97. case 'close-right':
  98. this.closeRight(vkey)
  99. break
  100. case 'close-left':
  101. this.closeLeft(vkey)
  102. break
  103. case 'close-all':
  104. this.closeAll(vkey)
  105. break
  106. default:
  107. case 'close-that':
  108. this.closeThat(vkey)
  109. break
  110. }
  111. },
  112. renderTabPaneMenu (e) {
  113. return (
  114. <a-menu {...{ on: { click: this.closeMenuClick } }}>
  115. <a-menu-item key="close-that" data-vkey={e}>关闭当前标签</a-menu-item>
  116. <a-menu-item key="close-right" data-vkey={e}>关闭右侧</a-menu-item>
  117. <a-menu-item key="close-left" data-vkey={e}>关闭左侧</a-menu-item>
  118. <a-menu-item key="close-all" data-vkey={e}>关闭全部</a-menu-item>
  119. </a-menu>
  120. )
  121. },
  122. // render
  123. renderTabPane (title, keyPath) {
  124. const menu = this.renderTabPaneMenu(keyPath)
  125. return (
  126. <a-dropdown overlay={menu} trigger={['contextmenu']}>
  127. <span style={{ userSelect: 'none' }}>{ title }</span>
  128. </a-dropdown>
  129. )
  130. }
  131. },
  132. watch: {
  133. '$route': function (newVal) {
  134. this.activeKey = newVal.fullPath
  135. if (this.fullPathList.indexOf(newVal.fullPath) < 0) {
  136. this.fullPathList.push(newVal.fullPath)
  137. this.pages.push(newVal)
  138. }
  139. },
  140. activeKey: function (newPathKey) {
  141. this.$router.push({ path: newPathKey })
  142. }
  143. },
  144. render () {
  145. const { onEdit, $data: { pages } } = this
  146. const panes = pages.map(page => {
  147. return (
  148. <a-tab-pane
  149. style={{ height: 0 }}
  150. tab={this.renderTabPane(page.meta.title, page.fullPath)}
  151. key={page.fullPath} closable={pages.length > 1}
  152. >
  153. </a-tab-pane>)
  154. })
  155. return (
  156. <div class="ant-pro-multi-tab">
  157. <div class="ant-pro-multi-tab-wrapper">
  158. <a-tabs
  159. hideAdd
  160. type={'editable-card'}
  161. v-model={this.activeKey}
  162. tabBarStyle={{ background: '#FFF', margin: 0, paddingLeft: '16px', paddingTop: '1px' }}
  163. {...{ on: { edit: onEdit } }}>
  164. {panes}
  165. </a-tabs>
  166. </div>
  167. </div>
  168. )
  169. }
  170. }
  171. </script>