fix(tabs): refactor before-leave prop (#1420)

* feat: update before-leave prop

* fix: optimization

* fix: update log

* feat: update test

* fix: add debug demo

* feat: optimization

* fix: add debug demo

* feat: optimization

* feat: optimization

Co-authored-by: unknown <liyang@xiaoyouzi.com>
This commit is contained in:
小魔王 2021-10-29 03:15:45 +08:00 committed by GitHub
parent bbf5412c26
commit 75879999c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 7 deletions

View File

@ -1,5 +1,11 @@
# CHANGELOG # CHANGELOG
## Pending
## Fixes
- Fix `n-tabs` switch tab does not work when adding a new tab, closes [#1417](https://github.com/TuSimple/naive-ui/issues/1417).
## 2.20.0 (2021-10-28) ## 2.20.0 (2021-10-28)
### Breaking Changes ### Breaking Changes

View File

@ -1,5 +1,11 @@
# CHANGELOG # CHANGELOG
## Pending
## Fixes
- 修复 `n-tabs` 在新增 tab 后切换 tab 无法生效,关闭 [#1417]https://github.com/TuSimple/naive-ui/issues/1417)
## 2.20.0 (2021-10-28) ## 2.20.0 (2021-10-28)
### Breaking Changes ### Breaking Changes

View File

@ -51,9 +51,8 @@ export default defineComponent({
return return
} }
const { name: nameProp } = props const { name: nameProp } = props
const id = ++nextTabNameRef.id
if (nameProp !== valueRef.value) { if (nameProp !== valueRef.value) {
if (nameProp === nextTabNameRef.value) return
nextTabNameRef.value = nameProp
const { value: onBeforeLeave } = onBeforeLeaveRef const { value: onBeforeLeave } = onBeforeLeaveRef
if (!onBeforeLeave) { if (!onBeforeLeave) {
handleTabClick(nameProp) handleTabClick(nameProp)
@ -61,7 +60,7 @@ export default defineComponent({
void Promise.resolve( void Promise.resolve(
(onBeforeLeave as OnBeforeLeaveImpl)(props.name, valueRef.value) (onBeforeLeave as OnBeforeLeaveImpl)(props.name, valueRef.value)
).then((allowLeave) => { ).then((allowLeave) => {
if (allowLeave) { if (allowLeave && nextTabNameRef.id === id) {
handleTabClick(nameProp) handleTabClick(nameProp)
} }
}) })

View File

@ -144,7 +144,10 @@ export default defineComponent({
uncontrolledValueRef uncontrolledValueRef
) )
const nextTabNameRef = { value: mergedValueRef.value } const nextTabNameRef = { id: 0 }
watch(mergedValueRef, () => {
nextTabNameRef.id = 0
})
const tabWrapperStyleRef = computed(() => { const tabWrapperStyleRef = computed(() => {
if (!props.justifyContent || props.type === 'card') return undefined if (!props.justifyContent || props.type === 'card') return undefined

View File

@ -24,7 +24,7 @@ export interface TabsInjection {
closableRef: Ref<boolean> closableRef: Ref<boolean>
tabStyleRef: Ref<string | CSSProperties | undefined> tabStyleRef: Ref<string | CSSProperties | undefined>
paneStyleRef: Ref<string | CSSProperties | undefined> paneStyleRef: Ref<string | CSSProperties | undefined>
nextTabNameRef: { value: string | number | null } nextTabNameRef: { id: number }
onBeforeLeaveRef: Ref<OnBeforeLeave | undefined> onBeforeLeaveRef: Ref<OnBeforeLeave | undefined>
handleTabClick: (panelName: string | number) => void handleTabClick: (panelName: string | number) => void
handleClose: (panelName: string | number) => void handleClose: (panelName: string | number) => void

View File

@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils'
import { h } from 'vue' import { h } from 'vue'
import { NTabPane, NTabs } from '../index' import { NTabPane, NTabs } from '../index'
import { AddIcon } from '../../_internal/icons' import { AddIcon } from '../../_internal/icons'
import { sleep } from 'seemly'
describe('n-tabs', () => { describe('n-tabs', () => {
it('should work with import on demand', () => { it('should work with import on demand', () => {
@ -42,15 +43,20 @@ describe('n-tabs', () => {
}) })
}) })
it('should show AddIcon with `addable` prop', () => { it('should show AddIcon with `addable` prop', async () => {
const onAdd = jest.fn()
const wrapper = mount(NTabs, { const wrapper = mount(NTabs, {
props: { props: {
type: 'card', type: 'card',
addable: true addable: true,
onAdd
} }
}) })
expect(wrapper.findComponent(AddIcon).exists()).toBe(true) expect(wrapper.findComponent(AddIcon).exists()).toBe(true)
const addIcon = wrapper.find('.n-tabs-tab--addable')
await addIcon.trigger('click')
expect(onAdd).toHaveBeenCalled()
}) })
it('should work with `justify-content` prop', async () => { it('should work with `justify-content` prop', async () => {
@ -136,4 +142,52 @@ describe('n-tabs', () => {
expect(wrapper.find('.test-if').exists()).toEqual(false) expect(wrapper.find('.test-if').exists()).toEqual(false)
expect(wrapper.find('.test-show-lazy').exists()).toEqual(true) expect(wrapper.find('.test-show-lazy').exists()).toEqual(true)
}) })
it('should work with `on-before-leave` prop', async () => {
const wrapper = mount(NTabs, {
props: {
type: 'card',
defaultValue: '3',
onBeforeLeave: (name: string) => {
switch (name) {
case '1':
return false
case '2':
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
return new Promise((resolve) => {
setTimeout(() => {
resolve(true)
}, 1000)
}) as Promise<boolean>
default:
return true
}
}
},
slots: {
default: () => [
h(NTabPane, {
tab: '1',
name: '1'
}),
h(NTabPane, {
tab: '2',
name: '2'
}),
h(NTabPane, {
tab: '3',
name: '3'
})
]
}
})
const tabs = wrapper.findAll('.n-tabs-tab')
expect(tabs[2].classes()).toContain('n-tabs-tab--active')
await tabs[0].trigger('click')
expect(tabs[2].classes()).toContain('n-tabs-tab--active')
await tabs[1].trigger('click')
expect(tabs[2].classes()).toContain('n-tabs-tab--active')
await sleep(1000)
expect(tabs[1].classes()).toContain('n-tabs-tab--active')
})
}) })