Skip to content

Commit 9eac225

Browse files
authored
feat(tabs): 支持tab-position属性 (#830)
1 parent 49aca22 commit 9eac225

File tree

11 files changed

+393
-113
lines changed

11 files changed

+393
-113
lines changed

packages/devui-vue/devui/tabs/__tests__/tabs.spec.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const dotTabsNavPills = dotTabsNs.e('nav--pills');
1515
const dotTabsNavOptions = dotTabsNs.e('nav--options');
1616
const dotTabsNavWrapped = dotTabsNs.e('nav--wrapped');
1717
const dotTabsNavSlider = dotTabsNs.e('nav--slider');
18+
const dotTabsNavTop = dotTabsNs.e('nav--top');
19+
const dotTabsNavRight = dotTabsNs.e('nav--right');
20+
const dotTabsNavBottom = dotTabsNs.e('nav--bottom');
21+
const dotTabsNavLeft = dotTabsNs.e('nav--left');
1822

1923
describe('Tabs', () => {
2024
let wrapper: VueWrapper<ComponentPublicInstance>;
@@ -236,4 +240,49 @@ describe('Tabs', () => {
236240
await nextTick();
237241
expect(wrapper.find('#tab1').text()).toBe('abc');
238242
});
243+
244+
it('tab-position worked', async () => {
245+
wrapper = mount({
246+
setup() {
247+
const id = ref('tab1');
248+
249+
return () => {
250+
return (
251+
<Tabs v-model={id.value}>
252+
<Tab id="tab1" title="Tab1">
253+
Tab1 Content
254+
</Tab>
255+
<Tab id="tab2" title="Tab2">
256+
Tab2 Content
257+
</Tab>
258+
<Tab id="tab3" title="Tab3">
259+
Tab3 Content
260+
</Tab>
261+
</Tabs>
262+
);
263+
};
264+
},
265+
});
266+
267+
await nextTick();
268+
expect(wrapper.find(dotTabsNavTop).exists()).toBe(true);
269+
270+
wrapper.setProps({
271+
tabPosition: 'right',
272+
});
273+
await nextTick();
274+
expect(wrapper.find(dotTabsNavRight).exists()).toBe(true);
275+
276+
wrapper.setProps({
277+
tabPosition: 'bottom',
278+
});
279+
await nextTick();
280+
expect(wrapper.find(dotTabsNavBottom).exists()).toBe(true);
281+
282+
wrapper.setProps({
283+
tabPosition: 'left',
284+
});
285+
await nextTick();
286+
expect(wrapper.find(dotTabsNavLeft).exists()).toBe(true);
287+
});
239288
});

packages/devui-vue/devui/tabs/src/components/tab-nav/composables/use-tab-nav-function.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@ export function useTabNavFunction(
1515
setTimeout(() => {
1616
const tabEle = tabsEle.value.querySelector('#' + props.modelValue + '.active');
1717
if (tabEle) {
18-
data.offsetLeft = tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left;
18+
if (['top', 'bottom'].includes(props.tabPosition)) {
19+
data.offsetLeft = tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left;
20+
} else {
21+
data.offsetTop = tabEle.getBoundingClientRect().top - tabsEle.value.getBoundingClientRect().top;
22+
data.offsetHeight = tabEle.getBoundingClientRect().height;
23+
}
1924
data.offsetWidth = tabEle.getBoundingClientRect().width;
2025
}
2126
});
@@ -49,7 +54,12 @@ export function useTabNavFunction(
4954
if (tab && !tab.disabled) {
5055
tabs.state.active = item.id;
5156
if (props.type === 'slider' && tabEl && tabsEle) {
52-
data.offsetLeft = tabEl.getBoundingClientRect().left - tabsEle.value.nativeElement.getBoundingClientRect().left;
57+
if (['left', 'right'].includes(props.tabPosition)) {
58+
data.offsetLeft = tabEl.getBoundingClientRect().left - tabsEle.value.nativeElement.getBoundingClientRect().left;
59+
} else {
60+
data.offsetTop = tabEl.getBoundingClientRect().top - tabsEle.value.nativeElement.getBoundingClientRect().top;
61+
data.offsetHeight = tabEl.getBoundingClientRect().height;
62+
}
5363
data.offsetWidth = tabEl.getBoundingClientRect().width;
5464
}
5565
ctx.emit('active-tab-change', tab.id);
Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import { computed, StyleValue, toRefs } from 'vue';
22
import { TabsProps } from '../../../tabs-types';
3-
import { UseTabNavRender } from '../tab-nav-types';
3+
import { OffSetData, UseTabNavRender } from '../tab-nav-types';
44
import { useNamespace } from '../../../../../shared/hooks/use-namespace';
55

66
const ns = useNamespace('tabs');
77

8-
export function useTabNavRender(props: TabsProps): UseTabNavRender {
9-
const { cssClass, vertical, customWidth } = toRefs(props);
8+
export function useTabNavRender(props: TabsProps, data: OffSetData): UseTabNavRender {
9+
const { cssClass, tabPosition, customWidth } = toRefs(props);
1010

1111
const ulClasses = computed(() => ({
1212
[ns.e('nav')]: true,
1313
[ns.em('nav', props.type)]: true,
1414
[cssClass.value]: Boolean(cssClass.value),
15-
[ns.e('stacked')]: vertical.value,
15+
[ns.em('nav', 'top')]: tabPosition.value === 'top',
16+
[ns.em('nav', 'right')]: tabPosition.value === 'right',
17+
[ns.em('nav', 'bottom')]: tabPosition.value === 'bottom',
18+
[ns.em('nav', 'left')]: tabPosition.value === 'left',
1619
}));
1720

1821
const aClasses = computed(() => ({
@@ -23,5 +26,20 @@ export function useTabNavRender(props: TabsProps): UseTabNavRender {
2326
width: props.customWidth ? props.customWidth : '',
2427
};
2528

26-
return { ulClasses, aClasses, customStyle };
29+
const sliderAnimationStyle = computed(() => {
30+
if (['top', 'bottom'].includes(props.tabPosition)) {
31+
return {
32+
left: data.offsetLeft + 'px',
33+
width: data.offsetWidth + 'px',
34+
};
35+
} else {
36+
return {
37+
top: data.offsetTop + 'px',
38+
height: data.offsetHeight + 'px',
39+
width: data.offsetWidth + 'px',
40+
};
41+
}
42+
});
43+
44+
return { ulClasses, aClasses, customStyle, sliderAnimationStyle };
2745
}

packages/devui-vue/devui/tabs/src/components/tab-nav/tab-nav-types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ export interface UseTabNavRender {
44
ulClasses: ComputedRef<Record<string, boolean>>;
55
aClasses: ComputedRef<Record<string, boolean>>;
66
customStyle: StyleValue;
7+
sliderAnimationStyle: ComputedRef<Record<string, string | undefined>>;
78
}
89

910
export interface OffSetData {
1011
offsetLeft: number;
1112
offsetWidth: number;
13+
offsetTop: number;
14+
offsetHeight: number;
1215
id: null;
1316
}
1417

0 commit comments

Comments
 (0)