MultiTab.vue 4.7 KB

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