tabs.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import { useStorage } from '@vueuse/core'
  2. import { acceptHMRUpdate, defineStore } from 'pinia'
  3. import type { RouteRecordNameGeneric } from 'vue-router'
  4. export type Key = string | number | undefined
  5. export interface Tab {
  6. id?: Key
  7. path: string
  8. icon?: string
  9. title?: string
  10. name?: RouteRecordNameGeneric
  11. componentName?: string
  12. locked?: boolean
  13. pinned?: boolean
  14. keepAlive?: boolean
  15. }
  16. export const useTabsStore = defineStore('tabsStore', () => {
  17. const tabs = useStorage<Tab[]>('tabs', [])
  18. const tabActivePath = useStorage<string>('tabActivePath', '')
  19. function findTabIndex(id: Key) {
  20. return tabs.value.findIndex((tab) => tab.id === id)
  21. }
  22. function sortTabs() {
  23. tabs.value.sort((a, b) => {
  24. if (a.pinned && !b.pinned) return -1
  25. if (!a.pinned && b.pinned) return 1
  26. return 0
  27. })
  28. }
  29. function createTab(tab: Tab) {
  30. if (!tabs.value.some(({ path }) => path === tab.path)) {
  31. const id = Date.now()
  32. tabs.value.push({ ...tab, id })
  33. if (tab.pinned) {
  34. sortTabs()
  35. }
  36. }
  37. setTabActivePath(tab.path)
  38. }
  39. function getTab(tabId: Key) {
  40. return tabs.value.find(({ id }) => id === tabId)
  41. }
  42. function updateTab(id: Key, updateProperties: Partial<Tab>) {
  43. const index = findTabIndex(id)
  44. if (index !== -1) {
  45. const targetTab = tabs.value[index]
  46. tabs.value[index] = { ...targetTab, ...updateProperties }
  47. if ('pinned' in updateProperties && updateProperties.pinned !== targetTab.pinned) {
  48. sortTabs()
  49. }
  50. }
  51. }
  52. function setTabs(value: Tab[]) {
  53. tabs.value = value
  54. }
  55. function removeTab(tabIds: Key | Key[]) {
  56. const removeIdsSet = new Set(Array.isArray(tabIds) ? tabIds : [tabIds])
  57. const nextTabs: Tab[] = []
  58. let activeIndex = -1
  59. for (let i = 0; i < tabs.value.length; i++) {
  60. const tab = tabs.value[i]
  61. if (tab.path === tabActivePath.value) activeIndex = i
  62. if (!removeIdsSet.has(tab.id)) nextTabs.push(tab)
  63. }
  64. if (activeIndex !== -1 && removeIdsSet.has(tabs.value[activeIndex].id)) {
  65. let nextActivePath = ''
  66. for (let i = activeIndex + 1; i < tabs.value.length; i++) {
  67. if (!removeIdsSet.has(tabs.value[i].id)) {
  68. nextActivePath = tabs.value[i].path
  69. break
  70. }
  71. }
  72. if (!nextActivePath) {
  73. for (let i = activeIndex - 1; i >= 0; i--) {
  74. if (!removeIdsSet.has(tabs.value[i].id)) {
  75. nextActivePath = tabs.value[i].path
  76. break
  77. }
  78. }
  79. }
  80. if (nextActivePath) {
  81. setTabActivePath(nextActivePath)
  82. } else {
  83. setTabActivePath('/')
  84. }
  85. }
  86. tabs.value = nextTabs
  87. }
  88. function clearTabs() {
  89. tabs.value = []
  90. }
  91. function getRemovableIdsBefore(id: Key) {
  92. const removableIds: Key[] = []
  93. for (const tab of tabs.value) {
  94. if (tab.id === id) break
  95. if (!tab.locked && !tab.pinned) {
  96. removableIds.push(tab.id)
  97. }
  98. }
  99. return removableIds
  100. }
  101. function getRemovableIdsAfter(id: Key) {
  102. const removableIds: Key[] = []
  103. for (let i = tabs.value.length - 1; i >= 0; i--) {
  104. if (tabs.value[i].id === id) break
  105. if (!tabs.value[i].locked && !tabs.value[i].pinned) {
  106. removableIds.push(tabs.value[i].id)
  107. }
  108. }
  109. return removableIds
  110. }
  111. function getRemovableIdsOther(id: Key) {
  112. const removableIds: Key[] = []
  113. for (const tab of tabs.value) {
  114. if (tab.id !== id && !tab.locked && !tab.pinned) {
  115. removableIds.push(tab.id)
  116. }
  117. }
  118. return removableIds
  119. }
  120. function getRemovableIds() {
  121. const removableIds: Key[] = []
  122. for (const tab of tabs.value) {
  123. if (!tab.locked && !tab.pinned) {
  124. removableIds.push(tab.id)
  125. }
  126. }
  127. return removableIds
  128. }
  129. function setTabActivePath(key: string) {
  130. tabActivePath.value = key
  131. }
  132. return {
  133. tabs,
  134. tabActivePath,
  135. setTabActivePath,
  136. getTab,
  137. createTab,
  138. updateTab,
  139. removeTab,
  140. setTabs,
  141. clearTabs,
  142. getRemovableIdsBefore,
  143. getRemovableIdsAfter,
  144. getRemovableIdsOther,
  145. getRemovableIds,
  146. }
  147. })
  148. if (import.meta.hot) {
  149. import.meta.hot.accept(acceptHMRUpdate(useTabsStore, import.meta.hot))
  150. }