refactor(Cascader): refactor with composition api

This commit is contained in:
chenjiahan 2020-12-21 22:41:47 +08:00
parent 4d6b1d2875
commit bf497eed33

View File

@ -1,4 +1,7 @@
import { nextTick, reactive, watch } from 'vue';
import { createNamespace } from '../utils'; import { createNamespace } from '../utils';
// Components
import Tab from '../tab'; import Tab from '../tab';
import Tabs from '../tabs'; import Tabs from '../tabs';
import Icon from '../icon'; import Icon from '../icon';
@ -23,36 +26,13 @@ export default createComponent({
emits: ['close', 'change', 'finish', 'update:modelValue'], emits: ['close', 'change', 'finish', 'update:modelValue'],
data() { setup(props, { slots, emit }) {
return { const state = reactive({
tabs: [], tabs: [],
activeTab: 0, activeTab: 0,
}; });
},
watch: { const getSelectedOptionsByValue = (options, value) => {
options: {
deep: true,
handler: 'updateTabs',
},
modelValue(value) {
if (value || value === 0) {
const values = this.tabs.map((tab) => tab.selectedOption?.value);
if (values.indexOf(value) !== -1) {
return;
}
}
this.updateTabs();
},
},
created() {
this.updateTabs();
},
methods: {
getSelectedOptionsByValue(options, value) {
for (let i = 0; i < options.length; i++) { for (let i = 0; i < options.length; i++) {
const option = options[i]; const option = options[i];
@ -61,7 +41,7 @@ export default createComponent({
} }
if (option.children) { if (option.children) {
const selectedOptions = this.getSelectedOptionsByValue( const selectedOptions = getSelectedOptionsByValue(
option.children, option.children,
value value
); );
@ -70,19 +50,19 @@ export default createComponent({
} }
} }
} }
}, };
updateTabs() { const updateTabs = () => {
if (this.modelValue || this.modelValue === 0) { if (props.modelValue || props.modelValue === 0) {
const selectedOptions = this.getSelectedOptionsByValue( const selectedOptions = getSelectedOptionsByValue(
this.options, props.options,
this.modelValue props.modelValue
); );
if (selectedOptions) { if (selectedOptions) {
let optionsCursor = this.options; let optionsCursor = props.options;
this.tabs = selectedOptions.map((option) => { state.tabs = selectedOptions.map((option) => {
const tab = { const tab = {
options: optionsCursor, options: optionsCursor,
selectedOption: option, selectedOption: option,
@ -99,33 +79,33 @@ export default createComponent({
}); });
if (optionsCursor) { if (optionsCursor) {
this.tabs.push({ state.tabs.push({
options: optionsCursor, options: optionsCursor,
selectedOption: null, selectedOption: null,
}); });
} }
this.$nextTick(() => { nextTick(() => {
this.activeTab = this.tabs.length - 1; state.activeTab = state.tabs.length - 1;
}); });
return; return;
} }
} }
this.tabs = [ state.tabs = [
{ {
options: this.options, options: props.options,
selectedOption: null, selectedOption: null,
}, },
]; ];
}, };
onSelect(option, tabIndex) { const onSelect = (option, tabIndex) => {
this.tabs[tabIndex].selectedOption = option; state.tabs[tabIndex].selectedOption = option;
if (this.tabs.length > tabIndex + 1) { if (state.tabs.length > tabIndex + 1) {
this.tabs = this.tabs.slice(0, tabIndex + 1); state.tabs = state.tabs.slice(0, tabIndex + 1);
} }
if (option.children) { if (option.children) {
@ -134,18 +114,18 @@ export default createComponent({
selectedOption: null, selectedOption: null,
}; };
if (this.tabs[tabIndex + 1]) { if (state.tabs[tabIndex + 1]) {
this.$set(this.tabs, tabIndex + 1, nextTab); state.tabs[tabIndex + 1] = nextTab;
} else { } else {
this.tabs.push(nextTab); state.tabs.push(nextTab);
} }
this.$nextTick(() => { nextTick(() => {
this.activeTab++; state.activeTab++;
}); });
} }
const selectedOptions = this.tabs const selectedOptions = state.tabs
.map((tab) => tab.selectedOption) .map((tab) => tab.selectedOption)
.filter((item) => !!item); .filter((item) => !!item);
@ -154,36 +134,30 @@ export default createComponent({
tabIndex, tabIndex,
selectedOptions, selectedOptions,
}; };
this.$emit('update:modelValue', option.value); emit('update:modelValue', option.value);
this.$emit('change', eventParams); emit('change', eventParams);
if (!option.children) { if (!option.children) {
this.$emit('finish', eventParams); emit('finish', eventParams);
} }
}, };
onClose() { const onClose = () => {
this.$emit('close'); emit('close');
}, };
renderHeader() { const renderHeader = () => (
return (
<div class={bem('header')}> <div class={bem('header')}>
<h2 class={bem('title')}> <h2 class={bem('title')}>
{this.$slots.title ? this.$slots.title() : this.title} {slots.title ? slots.title() : props.title}
</h2> </h2>
{this.closeable ? ( {props.closeable ? (
<Icon <Icon name="cross" class={bem('close-icon')} onClick={onClose} />
name="cross"
class={bem('close-icon')}
onClick={this.onClose}
/>
) : null} ) : null}
</div> </div>
); );
},
renderOptions(options, selectedOption, tabIndex) { const renderOptions = (options, selectedOption, tabIndex) => {
const renderOption = (option) => { const renderOption = (option) => {
const isSelected = const isSelected =
selectedOption && option.value === selectedOption.value; selectedOption && option.value === selectedOption.value;
@ -191,9 +165,9 @@ export default createComponent({
return ( return (
<li <li
class={bem('option', { selected: isSelected })} class={bem('option', { selected: isSelected })}
style={{ color: isSelected ? this.activeColor : null }} style={{ color: isSelected ? props.activeColor : null }}
onClick={() => { onClick={() => {
this.onSelect(option, tabIndex); onSelect(option, tabIndex);
}} }}
> >
<span>{option.text}</span> <span>{option.text}</span>
@ -205,13 +179,13 @@ export default createComponent({
}; };
return <ul class={bem('options')}>{options.map(renderOption)}</ul>; return <ul class={bem('options')}>{options.map(renderOption)}</ul>;
}, };
renderTab(item, tabIndex) { const renderTab = (item, tabIndex) => {
const { options, selectedOption } = item; const { options, selectedOption } = item;
const title = selectedOption const title = selectedOption
? selectedOption.text ? selectedOption.text
: this.placeholder || t('select'); : props.placeholder || t('select');
return ( return (
<Tab <Tab
@ -220,32 +194,44 @@ export default createComponent({
unselected: !selectedOption, unselected: !selectedOption,
})} })}
> >
{this.renderOptions(options, selectedOption, tabIndex)} {renderOptions(options, selectedOption, tabIndex)}
</Tab> </Tab>
); );
}, };
renderTabs() { const renderTabs = () => (
return (
<Tabs <Tabs
v-model={[this.activeTab, 'active']} v-model={[state.activeTab, 'active']}
animated animated
swipeable swipeable
swipeThreshold={0} swipeThreshold={0}
class={bem('tabs')} class={bem('tabs')}
color={this.activeColor} color={props.activeColor}
> >
{this.tabs.map(this.renderTab)} {state.tabs.map(renderTab)}
</Tabs> </Tabs>
); );
},
},
render() { updateTabs();
return (
watch(() => props.options, updateTabs, { deep: true });
watch(
() => props.modelValue,
(value) => {
if (value || value === 0) {
const values = state.tabs.map((tab) => tab.selectedOption?.value);
if (values.indexOf(value) !== -1) {
return;
}
}
updateTabs();
}
);
return () => (
<div class={bem()}> <div class={bem()}>
{this.renderHeader()} {renderHeader()}
{this.renderTabs()} {renderTabs()}
</div> </div>
); );
}, },