Skip to content

Commit

Permalink
fix(tabs): 修复 vertical 方式 tab 数量过多时滚动定位不准确的问题 (#2996)
Browse files Browse the repository at this point in the history
  • Loading branch information
eiinu authored Mar 26, 2024
1 parent ff87bf9 commit 20bf628
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 121 deletions.
210 changes: 97 additions & 113 deletions src/packages/__VUE/tabs/__tests__/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { config, mount } from '@vue/test-utils'
import { nextTick, reactive } from 'vue'
import { nextTick, reactive, ref } from 'vue'
import { JoySmile, Dongdong } from '@nutui/icons-vue'
import { Sticky as NutSticky, Tabs, TabPane } from '@nutui/nutui'

Expand All @@ -15,27 +15,19 @@ afterAll(() => {
config.global.components = {}
})

test('base Tabs', () => {
const wrapper = mount(Tabs)
const rate = wrapper.find('.nut-tabs')
expect(rate.exists()).toBe(true)
})

test('base tabs props', async () => {
const wrapper = mount(Tabs, {
props: {
modelValue: '0',
background: '#f5f5f5',
color: '#f5f5f5',
direction: 'horizontal',
type: 'smile',
size: 'large',
'title-scroll': true
},
components: {
'nut-tabs': Tabs,
'nut-tab-pane': TabPane
}
test('Tabs: base tabs props', async () => {
const wrapper = mount(() => {
return (
<Tabs
modelValue={0}
background="#f5f5f5"
color="#f5f5f5"
direction="horizontal"
type="smile"
size="large"
titleScroll
></Tabs>
)
})
await nextTick()
const stepItem = wrapper.find('.nut-tabs__titles')
Expand All @@ -50,27 +42,24 @@ test('base tabs props', async () => {
expect(_stepItem3.classes()).toContain('scrollable')
})

test('base other props', async () => {
const wrapper = mount({
components: {
'nut-tabs': Tabs,
'nut-tab-pane': TabPane
},
template: `
<nut-tabs animatedTime="500" titleGutter="20">
<nut-tab-pane paneKey="1">123</nut-tab-pane>
<nut-tab-pane paneKey="2">456</nut-tab-pane>
</nut-tabs>
`
test('Tabs: base other props', async () => {
const wrapper = mount(() => {
return (
<Tabs animatedTime={500} titleGutter={20}>
<TabPane paneKey={1}>123</TabPane>
<TabPane paneKey={2}>456</TabPane>
</Tabs>
)
})
await nextTick()
const stepItem = wrapper.find('.nut-tabs__content')
expect((stepItem.element as HTMLElement).style.transitionDuration).toEqual('500ms')
const stepItem1 = wrapper.find('.nut-tabs__titles-item')
expect((stepItem1.element as HTMLElement).style.marginLeft).toEqual('20px')
expect((stepItem1.element as HTMLElement).style.paddingLeft).toEqual('20px')
})

test('base Tabs Slots', async () => {
test('Tabs: base Tabs Slots', async () => {
// TODO: template -> tsx
const wrapper = mount({
components: {
'nut-tabs': Tabs,
Expand Down Expand Up @@ -133,25 +122,24 @@ test('base Tabs Slots', async () => {
expect(tab4.exists()).toBe(true)
})

test('base Tabpane Props', async () => {
const wrapper = mount({
components: {
'nut-tabs': Tabs,
'nut-tab-pane': TabPane
},
template: `
<nut-tabs v-model="state.tab2value">
<nut-tab-pane title="Tab 1" pane-key="0"> </nut-tab-pane>
<nut-tab-pane title="Tab 2" pane-key="1" :disabled="true"> Tab 2 </nut-tab-pane>
<nut-tab-pane title="Tab 3" pane-key="2"> Tab 3 </nut-tab-pane>
</nut-tabs>
`,
setup() {
const state = reactive({
tab2value: '0'
})
return { state }
}
test('Tabs: base Tabpane Props', async () => {
const val = ref('0')
const wrapper = mount(() => {
return (
<Tabs v-model={val.value}>
<TabPane title="Tab 1" pane-key="0">
{' '}
</TabPane>
<TabPane title="Tab 2" pane-key="1" disabled>
{' '}
Tab 2{' '}
</TabPane>
<TabPane title="Tab 3" pane-key="2">
{' '}
Tab 3{' '}
</TabPane>
</Tabs>
)
})
await nextTick()
const tab = wrapper.findAll('.nut-tabs__titles-item')
Expand All @@ -164,25 +152,24 @@ test('base Tabpane Props', async () => {
expect(tab3[0].html()).toContain('Tab 1')
})

test('base Tabpane disabled swipeable', async () => {
const wrapper = mount({
components: {
'nut-tabs': Tabs,
'nut-tab-pane': TabPane
},
template: `
<nut-tabs v-model="state.tab2value" swipeable>
<nut-tab-pane title="Tab 1" pane-key="0"> </nut-tab-pane>
<nut-tab-pane title="Tab 2" pane-key="1" :disabled="true"> Tab 2 </nut-tab-pane>
<nut-tab-pane title="Tab 3" pane-key="2"> Tab 3 </nut-tab-pane>
</nut-tabs>
`,
setup() {
const state = reactive({
tab2value: '0'
})
return { state }
}
test('Tabs: base Tabpane disabled swipeable', async () => {
const val = ref('0')
const wrapper = mount(() => {
return (
<Tabs v-model={val.value} swipeable>
<TabPane title="Tab 1" pane-key="0">
{' '}
</TabPane>
<TabPane title="Tab 2" pane-key="1" disabled>
{' '}
Tab 2{' '}
</TabPane>
<TabPane title="Tab 3" pane-key="2">
{' '}
Tab 3{' '}
</TabPane>
</Tabs>
)
})
await nextTick()
const tab = wrapper.findAll('.nut-tabs__titles-item')
Expand All @@ -195,25 +182,24 @@ test('base Tabpane disabled swipeable', async () => {
expect(tab3[0].html()).toContain('Tab 1')
})

test('base click', async () => {
const wrapper = mount({
components: {
'nut-tabs': Tabs,
'nut-tab-pane': TabPane
},
template: `
<nut-tabs v-model="state.tab1value">
<nut-tab-pane title="Tab 1"> Tab 1 </nut-tab-pane>
<nut-tab-pane title="Tab 2"> Tab 2 </nut-tab-pane>
<nut-tab-pane title="Tab 3"> Tab 3 </nut-tab-pane>
</nut-tabs>
`,
setup() {
const state = reactive({
tab1value: '0'
})
return { state }
}
test('Tabs: base click', async () => {
const val = ref('0')
const wrapper = mount(() => {
return (
<Tabs v-model={val.value} swipeable>
<TabPane title="Tab 1" pane-key="0">
{' '}
</TabPane>
<TabPane title="Tab 2" pane-key="1">
{' '}
Tab 2{' '}
</TabPane>
<TabPane title="Tab 3" pane-key="2">
{' '}
Tab 3{' '}
</TabPane>
</Tabs>
)
})
await nextTick()
const tab = wrapper.find('.nut-tabs__titles-item')
Expand All @@ -223,27 +209,25 @@ test('base click', async () => {
expect((tab1.element as HTMLElement).style.transform).toEqual('translate3d(-0%, 0, 0)')
})

test('Tabs: direction=vertical & title-gutter', async () => {
const wrapper = mount({
components: {
'nut-tabs': Tabs,
'nut-tab-pane': TabPane
},
template: `
<nut-tabs direction="vertical" title-gutter="10">
<nut-tab-pane pane-key="1" title="Tab 1"> Tab 1 </nut-tab-pane>
<nut-tab-pane pane-key="2" title="Tab 2"> Tab 2 </nut-tab-pane>
<nut-tab-pane pane-key="3" title="Tab 3"> Tab 3 </nut-tab-pane>
</nut-tabs>
`,
setup() {
const state = reactive({
tab1value: '0'
})
return { state }
}
test('Tabs: Tabs: direction=vertical & title-gutter', async () => {
const wrapper = mount(() => {
return (
<Tabs direction="vertical" title-gutter="10">
<TabPane title="Tab 1" pane-key="0">
{' '}
</TabPane>
<TabPane title="Tab 2" pane-key="1">
{' '}
Tab 2{' '}
</TabPane>
<TabPane title="Tab 3" pane-key="2">
{' '}
Tab 3{' '}
</TabPane>
</Tabs>
)
})
await nextTick()
const tab = wrapper.find('.nut-tabs__titles-item')
expect(tab.html()).includes('margin-top: 10px')
expect(tab.html()).includes('padding-top: 10px')
})
10 changes: 4 additions & 6 deletions src/packages/__VUE/tabs/index.taro.vue
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,14 @@ export default create({
let to = 0
if (props.direction === 'vertical') {
const DEFAULT_PADDING = 11
const top = titleRects
.slice(0, currentIndex.value)
.reduce((prev: number, curr: RectItem) => prev + curr?.height + 0, DEFAULT_PADDING)
.reduce((prev: number, curr: RectItem) => prev + curr?.height, 0)
to = top - (navRectRef.value?.height - titleRect?.height) / 2
} else {
const DEFAULT_PADDING = 31
const left = titleRects
.slice(0, currentIndex.value)
.reduce((prev: number, curr: RectItem) => prev + curr?.width + 20, DEFAULT_PADDING)
.reduce((prev: number, curr: RectItem) => prev + curr?.width, 0)
to = left - (navRectRef.value?.width - titleRect?.width) / 2
}
Expand Down Expand Up @@ -398,9 +396,9 @@ export default create({
if (!props.titleGutter) return {}
const px = pxCheck(props.titleGutter)
if (props.direction === 'vertical') {
return { marginTop: px, marginBottom: px }
return { paddingTop: px, paddingBottom: px }
}
return { marginLeft: px, marginRight: px }
return { paddingLeft: px, paddingRight: px }
})
return {
titles,
Expand Down
4 changes: 2 additions & 2 deletions src/packages/__VUE/tabs/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,9 @@ export default create({
if (!props.titleGutter) return {}
const px = pxCheck(props.titleGutter)
if (props.direction === 'vertical') {
return { marginTop: px, marginBottom: px }
return { paddingTop: px, paddingBottom: px }
}
return { marginLeft: px, marginRight: px }
return { paddingLeft: px, paddingRight: px }
})
return {
Expand Down

0 comments on commit 20bf628

Please sign in to comment.