Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(comp:tabs): add onBeforeLeave prop #965

Merged
merged 1 commit into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion packages/components/tabs/__tests__/tabs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { MountingOptions, mount } from '@vue/test-utils'
import { h } from 'vue'

import { renderWork } from '@tests'
import { renderWork, wait } from '@tests'

import Tab from '../src/Tab'
import Tabs from '../src/Tabs'
Expand Down Expand Up @@ -201,5 +201,37 @@ describe('Tabs', () => {

expect(wrapper.findAll('.ix-tabs-pane').length).toBe(2)
})

test('onBeforeLeave work', async () => {
const onUpdateSelectedKey = vi.fn()
const wrapper = TabsMount({
props: {
selectedKey: 'tab3',
'onUpdate:selectedKey': onUpdateSelectedKey,
onBeforeLeave: key => {
switch (key) {
case 'tab1':
return false
case 'tab2':
return new Promise(resolve => {
setTimeout(() => {
resolve(true)
}, 1000)
}) as Promise<boolean>
default:
return true
}
},
},
})

const tabs = wrapper.findAll('.ix-tabs-nav-tab')
await tabs[0].trigger('click')
expect(onUpdateSelectedKey).toBeCalledTimes(0)
await tabs[1].trigger('click')
expect(onUpdateSelectedKey).toBeCalledTimes(0)
await wait(1000)
expect(onUpdateSelectedKey).toBeCalledWith('tab2')
})
})
})
1 change: 1 addition & 0 deletions packages/components/tabs/docs/Index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ order: 0
| `onTabClick` | 标签被点击的回调 | `(key: VKey, evt: Event) => void`| - | - | - |
| `onPreClick` | 滚动状态下,Pre按钮被点击的回调 | `(evt: Event) => void`| - | - | - |
| `onNextClick` | 滚动状态下,Next按钮被点击的回调 | `(evt: Event) => void`| - | - | - |
| `onBeforeLeave` | 切换标签之前的钩子函数,返回 `false` 或 promise resolve `false` 或 promise reject 会阻止切换 | `(key: VKey, oldKey?: VKey) => boolean \| Promise<boolean>`| - | - | - |

#### IxTabProps

Expand Down
16 changes: 10 additions & 6 deletions packages/components/tabs/src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { ComputedRef, Ref, VNode } from 'vue'

import { computed, defineComponent, nextTick, normalizeClass, provide, ref, vShow, watch, withDirectives } from 'vue'

import { curry, isNil, throttle } from 'lodash-es'
import { curry, isNil } from 'lodash-es'

import { useResizeObserver } from '@idux/cdk/resize'
import { addClass, callEmit, flattenNode, removeClass, useControlledProp } from '@idux/cdk/utils'
Expand Down Expand Up @@ -89,9 +89,13 @@ export default defineComponent({
const navPreClasses = curryNavPreNextClasses('pre', preReached)
const navNextClasses = curryNavPreNextClasses('next', nextReached)

const handleTabClick = (key: VKey, evt: Event) => {
callEmit(props.onTabClick, key, evt)
setSelectedKey(key)
const handleTabClick = async (key: VKey, evt: Event) => {
const leaveResult = callEmit(props.onBeforeLeave, key, selectedKey.value)
const result = await leaveResult
if (result !== false) {
callEmit(props.onTabClick, key, evt)
setSelectedKey(key)
}
}

const updateNavBarStyle = () => {
Expand Down Expand Up @@ -162,7 +166,7 @@ export default defineComponent({
updateNavBarStyle()
})

const onTabsResize = throttle(() => {
const onTabsResize = () => {
syncNavRelatedElSize()
if (hasScroll.value) {
//存在滚动状态时,因为会增加前进、后退两个按钮,所以需要重新获取navWrapper宽度
Expand All @@ -175,7 +179,7 @@ export default defineComponent({
} else {
updateNavBarStyle()
}
}, 10)
}

useResizeObserver(navWrapperElRef, onTabsResize)

Expand Down
2 changes: 1 addition & 1 deletion packages/components/tabs/src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface TabsContext {
selectedKey: Ref<VKey | undefined>
selectedElRef: Ref<HTMLElement | null>
mergedPrefixCls: ComputedRef<string>
handleTabClick: (key: VKey, evt: Event) => void
handleTabClick: (key: VKey, evt: Event) => Promise<void>
}

export const tabsToken: InjectionKey<TabsContext> = Symbol('tabsToken')
1 change: 1 addition & 0 deletions packages/components/tabs/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const tabsProps = {
onTabClick: [Function, Array] as PropType<MaybeArray<(key: VKey, evt: Event) => void>>,
onPreClick: [Function, Array] as PropType<MaybeArray<(evt: Event) => void>>,
onNextClick: [Function, Array] as PropType<MaybeArray<(evt: Event) => void>>,
onBeforeLeave: [Function, Array] as PropType<MaybeArray<(key: VKey, oldKey?: VKey) => boolean | Promise<boolean>>>,
} as const

export const tabProps = {
Expand Down