Skip to content

Commit fa872a8

Browse files
committed
feat(tabs): 为 addTab 和 remove 方法添加 options 参数
- 为 addTab 添加 active 选项,控制是否激活新添加的标签(默认 true) - 为 removeTab、removeOtherTabs、removeSideTabs 添加 activeNext 选项,控制移除后是否激活下一个标签(默认 true) - 新增 TabsHelperRemoveOptions 接口定义移除选项 - 添加 8 个测试用例覆盖新增的 options 参数功能
1 parent f9ac84f commit fa872a8

File tree

2 files changed

+164
-13
lines changed

2 files changed

+164
-13
lines changed

src/tabs/index.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ import { assign, isArray } from '@/utils'
55
type TabType = string
66
export type TabsSideType = 'left' | 'right'
77

8+
export interface TabsHelperRemoveOptions {
9+
/**
10+
* 当前激活的标签被移除时,是否激活下一个标签
11+
* @default true
12+
*/
13+
activeNext?: boolean
14+
}
15+
816
export interface TabsHelperOptions<TabData extends {}> {
917
/**
1018
* 判断标签是否可移除,返回假值时,标签将不可移除
@@ -99,8 +107,19 @@ export interface TabsHelper<TabData extends {}> {
99107
* 添加标签和标签数据,遇到重复的标签将会跳过,否则会在添加后更新激活标签
100108
* @param tab 标签
101109
* @param tabData 标签数据
110+
* @param options 选项
102111
*/
103-
addTab: (tab: TabType, tabData: TabData) => void
112+
addTab: (
113+
tab: TabType,
114+
tabData: TabData,
115+
options?: {
116+
/**
117+
* 是否激活该标签
118+
* @default true
119+
*/
120+
active?: boolean
121+
},
122+
) => void
104123
/**
105124
* 判断是否存在指定标签
106125
* @param tab 标签
@@ -134,18 +153,21 @@ export interface TabsHelper<TabData extends {}> {
134153
/**
135154
* 移除指定标签,若移除的是当前激活标签则移除前会自动激活下一个标签
136155
* @param tab 指定标签,默认为当前激活的标签
156+
* @param options 选项
137157
*/
138-
removeTab: (tab?: TabType) => Promise<void>
158+
removeTab: (tab?: TabType, options?: TabsHelperRemoveOptions) => Promise<void>
139159
/**
140160
* 移除除过指定标签的其他可移除的标签,并将指定标签设置为激活标签
141161
* @param tab 指定标签,默认为当前激活的标签
162+
* @param options 选项
142163
*/
143-
removeOtherTabs: (tab?: TabType) => Promise<void>
164+
removeOtherTabs: (tab?: TabType, options?: TabsHelperRemoveOptions) => Promise<void>
144165
/**
145166
* 移除指定标签的指定方向侧的所有可移除的标签,若当前激活的标签存在被移除的标签内,则将指定标签设置为激活标签
146167
* @param tab 指定标签,默认为当前激活的标签
168+
* @param options 选项
147169
*/
148-
removeSideTabs: (side: TabsSideType, tab?: TabType) => Promise<void>
170+
removeSideTabs: (side: TabsSideType, tab?: TabType, options?: TabsHelperRemoveOptions) => Promise<void>
149171
}
150172

151173
const defaultOptions = {
@@ -232,10 +254,10 @@ export function createTabsHelper<TabData extends {}>(
232254
return side === 'left' ? tabs.slice(0, index) : tabs.slice(index + 1)
233255
},
234256

235-
addTab(targetTab, tabData) {
257+
addTab(targetTab, tabData, { active = true } = {}) {
236258
if (!helper.hasTab(targetTab)) {
237259
setTab(targetTab, tabData)
238-
setActiveTab(targetTab)
260+
active && setActiveTab(targetTab)
239261
}
240262
},
241263

@@ -283,7 +305,7 @@ export function createTabsHelper<TabData extends {}>(
283305
return valid
284306
},
285307

286-
async removeTab(targetTab = helper.activeTab) {
308+
async removeTab(targetTab = helper.activeTab, { activeNext = true } = {}) {
287309
if (
288310
tabMap.value.size <= 1 ||
289311
!targetTab ||
@@ -299,12 +321,12 @@ export function createTabsHelper<TabData extends {}>(
299321
const nextTab = isActive ? tabs[index - 1] || tabs[index + 1] : null
300322

301323
// 如果移除的是当前激活的,则设置下一个需要激活的标签
302-
nextTab && setActiveTab(nextTab)
324+
nextTab && activeNext && setActiveTab(nextTab)
303325

304326
removeTabs([targetTab])
305327
},
306328

307-
async removeOtherTabs(targetTab = helper.activeTab) {
329+
async removeOtherTabs(targetTab = helper.activeTab, { activeNext = true } = {}) {
308330
if (!targetTab) {
309331
return
310332
}
@@ -317,12 +339,12 @@ export function createTabsHelper<TabData extends {}>(
317339
}
318340

319341
// 如果移除的不是当前激活的标签,则设置当前激活的标签为该标签
320-
targetTab !== helper.activeTab && setActiveTab(targetTab)
342+
activeNext && targetTab !== helper.activeTab && setActiveTab(targetTab)
321343

322344
removeTabs(otherTabs)
323345
},
324346

325-
async removeSideTabs(side, targetTab = helper.activeTab) {
347+
async removeSideTabs(side, targetTab = helper.activeTab, { activeNext = true } = {}) {
326348
if (!targetTab) {
327349
return
328350
}
@@ -337,7 +359,7 @@ export function createTabsHelper<TabData extends {}>(
337359
sideTabs.some(([tab]) => tab === helper.activeTab)
338360

339361
// 如果当前激活标签在该移除侧的标签中,则设置当前激活的标签为该标签
340-
activeInSide && setActiveTab(targetTab)
362+
activeInSide && activeNext && setActiveTab(targetTab)
341363

342364
removeTabs(sideTabs)
343365
},

tests/tabs/index.test.ts

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,26 @@ describe.concurrent('tabs', () => {
1616
expect(helper.activeTab).toBe('tab1')
1717
})
1818

19+
it('addTab 使用 active: false 添加标签但不激活', () => {
20+
const helper = createTabsHelper<TabData>()
21+
helper.addTab('tab1', { title: 'A' })
22+
helper.addTab('tab2', { title: 'B' }, { active: false })
23+
24+
expect(helper.getTabs()).toEqual([
25+
['tab1', { title: 'A' }],
26+
['tab2', { title: 'B' }],
27+
])
28+
expect(helper.activeTab).toBe('tab1') // 仍然是 tab1
29+
})
30+
31+
it('addTab 使用 active: true 显式激活标签', () => {
32+
const helper = createTabsHelper<TabData>()
33+
helper.addTab('tab1', { title: 'A' })
34+
helper.addTab('tab2', { title: 'B' }, { active: true })
35+
36+
expect(helper.activeTab).toBe('tab2')
37+
})
38+
1939
it('setTabData 更新已存在标签数据', () => {
2040
const helper = createTabsHelper<TabData>()
2141
helper.addTab('tab1', { title: 'Old' })
@@ -104,6 +124,38 @@ describe.concurrent('tabs', () => {
104124
expect(helper.activeTab).toBe('tab2')
105125
})
106126

127+
it('removeTab 使用 activeNext: false 移除标签但不激活下一个', async () => {
128+
const helper = createTabsHelper<TabData>()
129+
helper.addTab('tab1', {})
130+
helper.addTab('tab2', {})
131+
helper.addTab('tab3', {})
132+
133+
helper.activeTab = 'tab1'
134+
await helper.removeTab('tab1', { activeNext: false })
135+
136+
expect(helper.getTabs()).toEqual([
137+
['tab2', {}],
138+
['tab3', {}],
139+
])
140+
expect(helper.activeTab).toBe('tab1') // 仍然是 tab1(虽然已被移除)
141+
})
142+
143+
it('removeTab 使用 activeNext: true 显式激活下一个标签', async () => {
144+
const helper = createTabsHelper<TabData>()
145+
helper.addTab('tab1', {})
146+
helper.addTab('tab2', {})
147+
helper.addTab('tab3', {})
148+
149+
helper.activeTab = 'tab2'
150+
await helper.removeTab('tab2', { activeNext: true })
151+
152+
expect(helper.getTabs()).toEqual([
153+
['tab1', {}],
154+
['tab3', {}],
155+
])
156+
expect(helper.activeTab).toBe('tab1') // 激活前一个标签
157+
})
158+
107159
it('removeTab 当 beforeRemove 返回 false 时不移除标签', async () => {
108160
const helper = createTabsHelper<TabData>({
109161
beforeRemove: () => false,
@@ -135,6 +187,32 @@ describe.concurrent('tabs', () => {
135187
expect(helper.activeTab).toBe('c')
136188
})
137189

190+
it('removeOtherTabs 使用 activeNext: false 不激活目标标签', async () => {
191+
const helper = createTabsHelper<TabData>()
192+
helper.addTab('a', {})
193+
helper.addTab('b', {})
194+
helper.addTab('c', {})
195+
196+
helper.activeTab = 'a'
197+
await helper.removeOtherTabs('c', { activeNext: false })
198+
199+
expect(helper.getTabs()).toEqual([['c', {}]])
200+
expect(helper.activeTab).toBe('a') // 仍然是 a(虽然已被移除)
201+
})
202+
203+
it('removeOtherTabs 使用 activeNext: true 激活目标标签', async () => {
204+
const helper = createTabsHelper<TabData>()
205+
helper.addTab('a', {})
206+
helper.addTab('b', {})
207+
helper.addTab('c', {})
208+
209+
helper.activeTab = 'a'
210+
await helper.removeOtherTabs('b', { activeNext: true })
211+
212+
expect(helper.getTabs()).toEqual([['b', {}]])
213+
expect(helper.activeTab).toBe('b')
214+
})
215+
138216
it('removeOtherTabs 当无其他可移除标签时不执行', async () => {
139217
const helper = createTabsHelper<TabData>({
140218
isRemovable: ({ tabData }) => !tabData.isFixed,
@@ -165,9 +243,60 @@ describe.concurrent('tabs', () => {
165243
expect(helper.activeTab).toBe('b')
166244
})
167245

246+
it('removeSideTabs 移除右侧标签', async () => {
247+
const helper = createTabsHelper<TabData>()
248+
helper.addTab('a', {})
249+
helper.addTab('b', {})
250+
helper.addTab('c', {})
251+
helper.addTab('d', {})
252+
253+
helper.activeTab = 'c'
254+
await helper.removeSideTabs('right', 'b')
255+
256+
expect(helper.getTabs()).toEqual([
257+
['a', {}],
258+
['b', {}],
259+
])
260+
expect(helper.activeTab).toBe('b') // 激活的标签在右侧被移除,所以激活目标标签
261+
})
262+
263+
it('removeSideTabs 使用 activeNext: false 不激活目标标签', async () => {
264+
const helper = createTabsHelper<TabData>()
265+
helper.addTab('a', {})
266+
helper.addTab('b', {})
267+
helper.addTab('c', {})
268+
helper.addTab('d', {})
269+
270+
helper.activeTab = 'a'
271+
await helper.removeSideTabs('left', 'c', { activeNext: false })
272+
273+
expect(helper.getTabs()).toEqual([
274+
['c', {}],
275+
['d', {}],
276+
])
277+
expect(helper.activeTab).toBe('a') // 仍然是 a(虽然已被移除)
278+
})
279+
280+
it('removeSideTabs 使用 activeNext: true 当激活标签在移除侧时激活目标标签', async () => {
281+
const helper = createTabsHelper<TabData>()
282+
helper.addTab('a', {})
283+
helper.addTab('b', {})
284+
helper.addTab('c', {})
285+
helper.addTab('d', {})
286+
287+
helper.activeTab = 'd'
288+
await helper.removeSideTabs('right', 'b', { activeNext: true })
289+
290+
expect(helper.getTabs()).toEqual([
291+
['a', {}],
292+
['b', {}],
293+
])
294+
expect(helper.activeTab).toBe('b') // d 在右侧被移除,激活 b
295+
})
296+
168297
it('自定义选项覆盖默认行为', () => {
169298
const customOptions = {
170-
isRemovable: ({ tabData }) => tabData.isRemovable,
299+
isRemovable: ({ tabData }: { tabData: TabData }) => !!tabData.isRemovable,
171300
beforeRemove: () => Promise.resolve(true),
172301
}
173302

0 commit comments

Comments
 (0)