Skip to content

Commit 31ccca9

Browse files
authored
refactor(Tabs): refactor Tabs (#252)
1 parent c725114 commit 31ccca9

File tree

3 files changed

+126
-159
lines changed

3 files changed

+126
-159
lines changed
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
1-
import { defineComponent, inject } from 'vue'
2-
import { Tabs } from './tabs'
1+
import { defineComponent, inject } from 'vue';
2+
import { Tabs } from './tabs';
33

44
export default defineComponent({
55
name: 'DTab',
66
props: {
77
title: {
88
default: null,
9-
type: [String, Number]
9+
type: [String, Number],
1010
},
1111
id: {
1212
default: null,
13-
type: String
13+
type: String,
1414
},
1515
disabled: {
1616
type: Boolean,
17-
default: false
18-
}
17+
default: false,
18+
},
1919
},
2020
setup(props, { slots }) {
21-
const tabs = inject<Tabs>('tabs')
22-
tabs.state.slots.push(slots.dTabTitle)
23-
tabs.state.data.push(props)
21+
const tabs = inject<Tabs>('tabs');
22+
tabs.state.slots.push(slots.title);
23+
tabs.state.data.push(props);
2424
return () => {
25-
const { id } = props
25+
const { id } = props;
2626
const content =
2727
tabs.state.showContent && tabs.state.active === id ? (
2828
<div class='devui-tab-content'>
2929
<div role='tabpanel' class='devui-tab-pane in active'>
3030
{slots.default()}
3131
</div>
3232
</div>
33-
) : null
34-
return content
35-
}
36-
}
37-
})
33+
) : null;
34+
return content;
35+
};
36+
},
37+
});
Lines changed: 66 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,158 @@
1-
import {
2-
defineComponent,
3-
onBeforeMount,
4-
onMounted,
5-
onUpdated,
6-
PropType,
7-
provide,
8-
reactive,
9-
ref,
10-
Slot
11-
} from 'vue'
12-
import './tabs.scss'
1+
import { defineComponent, onBeforeMount, onMounted, onUpdated, PropType, provide, reactive, ref, Slot } from 'vue';
2+
import './tabs.scss';
133

14-
export type Active = string | number | null
15-
export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider'
4+
export type Active = string | number | null;
5+
export type TabsType = 'tabs' | 'pills' | 'options' | 'wrapped' | 'slider';
166
export interface Tabs {
17-
state: TabsState
7+
state: TabsState;
188
}
199
interface TabsState {
20-
data?: any[]
21-
showContent: boolean
22-
active: string
23-
slots: Slot[]
10+
data?: any[];
11+
showContent: boolean;
12+
active: string;
13+
slots: Slot[];
2414
}
2515
export default defineComponent({
2616
name: 'DTabs',
2717
props: {
2818
modelValue: {
2919
type: [String, Number],
30-
default: null
20+
default: null,
3121
},
3222

3323
type: {
3424
type: String as () => TabsType,
35-
default: 'tabs'
25+
default: 'tabs',
3626
},
3727
showContent: {
3828
type: Boolean,
39-
default: true
29+
default: true,
4030
},
4131
vertical: {
4232
type: Boolean,
43-
default: false
33+
default: false,
4434
},
4535
reactivable: {
4636
type: Boolean,
47-
default: true
37+
default: true,
4838
},
4939
customWidth: {
5040
type: String,
51-
default: ''
41+
default: '',
5242
},
5343
cssClass: {
5444
type: String,
55-
default: ''
45+
default: '',
5646
},
5747
beforeChange: {
5848
type: Function as PropType<(id: Active) => boolean>,
59-
default: null
60-
}
49+
default: null,
50+
},
6151
},
6252

63-
emits: ['update:modelValue', 'activeTabChange'],
53+
emits: ['update:modelValue', 'active-tab-change'],
6454
setup(props, { emit, slots }) {
65-
const tabsEle = ref(null)
66-
const data = reactive({ offsetLeft: 0, offsetWidth: 0, id: null })
55+
const tabsEle = ref(null);
56+
const data = reactive({ offsetLeft: 0, offsetWidth: 0, id: null });
6757
const state: TabsState = reactive({
6858
data: [],
6959
active: props.modelValue,
7060
showContent: props.showContent,
71-
slots: []
72-
})
61+
slots: [],
62+
});
7363
provide<Tabs>('tabs', {
74-
state
75-
})
64+
state,
65+
});
7666

7767
const canChange = function (currentTab: Active) {
78-
let changeResult = Promise.resolve(true)
68+
let changeResult = Promise.resolve(true);
7969
if (typeof props.beforeChange === 'function') {
80-
const result: any = props.beforeChange(currentTab)
70+
const result: any = props.beforeChange(currentTab);
8171
if (typeof result !== 'undefined') {
8272
if (result.then) {
83-
changeResult = result
73+
changeResult = result;
8474
} else {
85-
console.log(result)
86-
changeResult = Promise.resolve(result)
75+
changeResult = Promise.resolve(result);
8776
}
8877
}
8978
}
9079

91-
return changeResult
92-
}
80+
return changeResult;
81+
};
9382
const activeClick = function (item, tabEl?) {
9483
if (!props.reactivable && props.modelValue === item.id) {
95-
return
84+
return;
9685
}
9786
canChange(item.id).then((change) => {
9887
if (!change) {
99-
return
88+
return;
10089
}
101-
const tab = state.data.find((itemOption) => itemOption.id === item.id)
90+
const tab = state.data.find((itemOption) => itemOption.id === item.id);
10291
if (tab && !tab.disabled) {
103-
state.active = item.id
104-
emit('update:modelValue', tab.id)
92+
state.active = item.id;
93+
emit('update:modelValue', tab.id);
10594
if (props.type === 'slider' && tabEl && tabsEle) {
106-
this.offsetLeft =
107-
tabEl.getBoundingClientRect().left -
108-
this.tabsEle.nativeElement.getBoundingClientRect().left
109-
this.offsetWidth = tabEl.getBoundingClientRect().width
95+
this.offsetLeft = tabEl.getBoundingClientRect().left - this.tabsEle.nativeElement.getBoundingClientRect().left;
96+
this.offsetWidth = tabEl.getBoundingClientRect().width;
11097
}
111-
emit('activeTabChange', tab.id)
98+
emit('active-tab-change', tab.id);
11299
}
113-
})
114-
}
115-
const ulClass: string[] = [props.type]
116-
props.cssClass && ulClass.push(props.cssClass)
117-
props.vertical && ulClass.push('devui-nav-stacked')
100+
});
101+
};
102+
const ulClass: string[] = [props.type];
103+
props.cssClass && ulClass.push(props.cssClass);
104+
props.vertical && ulClass.push('devui-nav-stacked');
118105
onUpdated(() => {
119106
if (props.type === 'slider') {
120107
// 延时等待active样式切换至正确的tab
121108
setTimeout(() => {
122-
const tabEle = tabsEle.value.querySelector('#' + props.modelValue + '.active')
109+
const tabEle = tabsEle.value.querySelector('#' + props.modelValue + '.active');
123110
if (tabEle) {
124-
data.offsetLeft =
125-
tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left
126-
data.offsetWidth = tabEle.getBoundingClientRect().width
111+
data.offsetLeft = tabEle.getBoundingClientRect().left - tabsEle.value.getBoundingClientRect().left;
112+
data.offsetWidth = tabEle.getBoundingClientRect().width;
127113
}
128-
})
114+
});
129115
}
130-
})
116+
});
131117
onBeforeMount(() => {
132118
if (props.type !== 'slider' && props.modelValue === undefined && state.data.length > 0) {
133-
activeClick(state.data[0])
119+
activeClick(state.data[0]);
134120
}
135-
})
121+
});
136122
onMounted(() => {
137-
if (
138-
props.type === 'slider' &&
139-
props.modelValue === undefined &&
140-
state.data.length > 0 &&
141-
state.data[0]
142-
) {
143-
activeClick(state.data[0].tabsEle.value.getElementById(state.data[0].tabId))
123+
if (props.type === 'slider' && props.modelValue === undefined && state.data.length > 0 && state.data[0]) {
124+
activeClick(state.data[0].tabsEle.value.getElementById(state.data[0].tabId));
144125
}
145-
})
126+
});
146127
return () => {
147128
return (
148129
<div>
149-
<ul
150-
ref={tabsEle}
151-
role='tablist'
152-
class={`devui-nav devui-nav-${ulClass.join(' ')}`}
153-
id='devuiTabs11'
154-
>
130+
<ul ref={tabsEle} role='tablist' class={`devui-nav devui-nav-${ulClass.join(' ')}`} id='devuiTabs11'>
155131
{state.data.map((item, i) => {
156132
return (
157133
<li
158134
role='presentation'
159135
onClick={() => {
160-
activeClick(item)
136+
activeClick(item);
161137
}}
162-
class={
163-
(props.modelValue === (item.id || item.tabId) ? 'active' : '') +
164-
' ' +
165-
(item.disabled ? 'disabled' : '')
166-
}
167-
id={item.id || item.tabId}
168-
>
169-
<a
170-
role='tab'
171-
data-toggle={item.id}
172-
aria-expanded={props.modelValue === (item.id || item.tabId)}
173-
>
138+
class={(props.modelValue === (item.id || item.tabId) ? 'active' : '') + ' ' + (item.disabled ? 'disabled' : '')}
139+
id={item.id || item.tabId}>
140+
<a role='tab' data-toggle={item.id} aria-expanded={props.modelValue === (item.id || item.tabId)}>
174141
{state.slots[i] ? state.slots[i]() : <span>{item.title}</span>}
175142
</a>
176143
</li>
177-
)
144+
);
178145
})}
179146
<div
180147
class={`devui-nav-${props.type}-animation`}
181148
style={{
182149
left: data.offsetLeft + 'px',
183-
width: data.offsetWidth + 'px'
184-
}}
185-
></div>
150+
width: data.offsetWidth + 'px',
151+
}}></div>
186152
</ul>
187153
{slots.default()}
188154
</div>
189-
)
190-
}
191-
}
192-
})
155+
);
156+
};
157+
},
158+
});

0 commit comments

Comments
 (0)