MultiTab.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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, oldVal) {
  121. // 父页面(列表)进入子页面(编辑、详情)再返回至子页面时关闭子页面页签
  122. if (oldVal && oldVal.name && newVal.query.closeLastOldTab) {
  123. this.remove(oldVal.name) // 关闭子页面
  124. }
  125. this.activeKey = newVal.name
  126. const index = this.tabsList.indexOf(newVal.name)
  127. // 解决页面地址相同参数不同时打开多个页签问题(例 详情页id或sn不同时)
  128. if (index < 0) { // 不存在
  129. this.tabsList.push(newVal.name)
  130. this.pages.push(newVal)
  131. } else { // 已存在
  132. this.pages.splice(index, 1, newVal)
  133. }
  134. },
  135. activeKey: function (newPathKey) {
  136. const row = this.pages.find(item => item.name == newPathKey)
  137. // console.log(row.fullPath)
  138. this.$router.push({ path: row.fullPath })
  139. }
  140. },
  141. render () {
  142. const { onEdit, $data: { pages } } = this
  143. const panes = pages.map(page => {
  144. return (
  145. <a-tab-pane
  146. style={{ height: 0 }}
  147. key={page.name} closable={pages.length > 1}
  148. >
  149. <span slot="tab">
  150. {this.renderTabPane(page.meta.customTitle || page.meta.title, page.name)}
  151. </span>
  152. </a-tab-pane>)
  153. })
  154. return (
  155. <div class="ant-pro-mu lti-tab">
  156. <div class="ant-pro-multi-tab-wrapper">
  157. <a-tabs
  158. hideAdd
  159. type={'editable-card'}
  160. v-model={this.activeKey}
  161. tabBarStyle={{ background: '#FFF', margin: 0, paddingLeft: '16px', paddingTop: '1px' }}
  162. {...{ on: { edit: onEdit } }}>
  163. {panes}
  164. </a-tabs>
  165. </div>
  166. </div>
  167. )
  168. }
  169. }
  170. </script>