feat(Cascader): add option slot (#9036)

* feat(Cascader): add option-text slot

* chore: adjust slot
This commit is contained in:
neverland 2021-07-15 14:44:07 +08:00 committed by GitHub
parent 69524def7b
commit 4de5f5ac5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 40 deletions

View File

@ -59,11 +59,7 @@ export default defineComponent({
activeTab: 0, activeTab: 0,
}); });
const { const { text: textKey, value: valueKey, children: childrenKey } = extend(
text: textKey,
value: valueKey,
children: childrenKey,
} = extend(
{ {
text: 'text', text: 'text',
value: 'value', value: 'value',
@ -210,22 +206,26 @@ export default defineComponent({
</div> </div>
); );
const renderOptions = ( const renderOption = (
options: CascaderOption[], option: CascaderOption,
selectedOption: CascaderOption | null, selectedOption: CascaderOption | null,
tabIndex: number tabIndex: number
) => { ) => {
const renderOption = (option: CascaderOption) => { const selected =
const isSelected =
selectedOption && option[valueKey] === selectedOption[valueKey]; selectedOption && option[valueKey] === selectedOption[valueKey];
const color = const color = option.color || (selected ? props.activeColor : undefined);
option.color || (isSelected ? props.activeColor : undefined);
const Text = slots.option ? (
slots.option({ option, selected })
) : (
<span>{option[textKey]}</span>
);
return ( return (
<li <li
class={[ class={[
bem('option', { bem('option', {
selected: isSelected, selected,
disabled: option.disabled, disabled: option.disabled,
}), }),
option.className, option.className,
@ -233,16 +233,25 @@ export default defineComponent({
style={{ color }} style={{ color }}
onClick={() => onSelect(option, tabIndex)} onClick={() => onSelect(option, tabIndex)}
> >
<span>{option[textKey]}</span> {Text}
{isSelected ? ( {selected ? (
<Icon name="success" class={bem('selected-icon')} /> <Icon name="success" class={bem('selected-icon')} />
) : null} ) : null}
</li> </li>
); );
}; };
return <ul class={bem('options')}>{options.map(renderOption)}</ul>; const renderOptions = (
}; options: CascaderOption[],
selectedOption: CascaderOption | null,
tabIndex: number
) => (
<ul class={bem('options')}>
{options.map((option) =>
renderOption(option, selectedOption, tabIndex)
)}
</ul>
);
const renderTab = (tab: CascaderTab, tabIndex: number) => { const renderTab = (tab: CascaderTab, tabIndex: number) => {
const { options, selectedOption } = tab; const { options, selectedOption } = tab;

View File

@ -235,9 +235,10 @@ export default {
### Slots ### Slots
| Name | Description | | Name | Description | SlotProps |
| ----- | ------------ | | --- | --- | --- |
| title | Custom title | | title | Custom title | - |
| option `v3.1.4` | Custom option text | _{ option: Option, selected: boolean }_ |
### CSS Variables ### CSS Variables

View File

@ -247,9 +247,10 @@ export default {
### Slots ### Slots
| 名称 | 说明 | | 名称 | 说明 | 参数 |
| ----- | -------------- | | --------------- | -------------- | --------------------------------------- |
| title | 自定义顶部标题 | | title | 自定义顶部标题 | - |
| option `v3.1.4` | 自定义选项文字 | _{ option: Option, selected: boolean }_ |
### 样式变量 ### 样式变量

View File

@ -5,6 +5,12 @@ exports[`should change close icon when using close-icon prop 1`] = `
</i> </i>
`; `;
exports[`should render option slot correctly 1`] = `
<li class="van-cascader__option">
Custom Option foo
</li>
`;
exports[`should render title slot correctly 1`] = ` exports[`should render title slot correctly 1`] = `
<h2 class="van-cascader__title"> <h2 class="van-cascader__title">
Custom Title Custom Title

View File

@ -88,6 +88,20 @@ test('should render title slot correctly', () => {
expect(wrapper.find('.van-cascader__title').html()).toMatchSnapshot(); expect(wrapper.find('.van-cascader__title').html()).toMatchSnapshot();
}); });
test('should render option slot correctly', async () => {
const option = { value: '1', text: 'foo' };
const wrapper = mount(Cascader, {
props: {
options: [option],
},
slots: {
option: ({ option }) => `Custom Option ${option.text}`,
},
});
await later();
expect(wrapper.find('.van-cascader__option').html()).toMatchSnapshot();
});
// TODO // TODO
// test('should select correct option when value changed', async () => { // test('should select correct option when value changed', async () => {
// const wrapper = mount(Cascader, { // const wrapper = mount(Cascader, {