mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
refactor(Cascader): refactor with composition api
This commit is contained in:
parent
4d6b1d2875
commit
bf497eed33
@ -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>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user