mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Cascader): add options-top slot (#9732)
* feat(Cascader): add option-top slot * refactor: use watch to listen for activeTab * test(Cascader): Add the options-top slot test * docs(Cascader): update the document 完成新功能https://github.com/youzan/vant/issues/9716 * chore(Cascader): api modification
This commit is contained in:
parent
33d777d6b2
commit
94539d8f74
@ -258,6 +258,9 @@ export default defineComponent({
|
|||||||
unselected: !selected,
|
unselected: !selected,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
{slots['options-top']
|
||||||
|
? slots['options-top']({ activeTab: activeTab.value })
|
||||||
|
: null}
|
||||||
{renderOptions(options, selected, tabIndex)}
|
{renderOptions(options, selected, tabIndex)}
|
||||||
</Tab>
|
</Tab>
|
||||||
);
|
);
|
||||||
@ -278,7 +281,6 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
|
|
||||||
updateTabs();
|
updateTabs();
|
||||||
|
|
||||||
watch(() => props.options, updateTabs, { deep: true });
|
watch(() => props.options, updateTabs, { deep: true });
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
|
@ -197,6 +197,54 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Custom Content
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-cascader
|
||||||
|
v-model="code"
|
||||||
|
title="Select Area"
|
||||||
|
:options="options"
|
||||||
|
:field-names="fieldNames"
|
||||||
|
>
|
||||||
|
<template #options-top="{ activeTab }">
|
||||||
|
<span>Current level {{activeTab}}</span>
|
||||||
|
</template>
|
||||||
|
</van-cascader>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const code = ref('');
|
||||||
|
const fieldNames = {
|
||||||
|
text: 'name',
|
||||||
|
value: 'code',
|
||||||
|
children: 'items',
|
||||||
|
};
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
name: 'Zhejiang',
|
||||||
|
code: '330000',
|
||||||
|
items: [{ name: 'Hangzhou', code: '330100' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Jiangsu',
|
||||||
|
code: '320000',
|
||||||
|
items: [{ name: 'Nanjing', code: '320100' }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
options,
|
||||||
|
fieldNames,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@ -239,6 +287,7 @@ export default {
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| title | Custom title | - |
|
| title | Custom title | - |
|
||||||
| option `v3.1.4` | Custom option text | _{ option: Option, selected: boolean }_ |
|
| option `v3.1.4` | Custom option text | _{ option: Option, selected: boolean }_ |
|
||||||
|
| options-top | Custom the content above options | - |
|
||||||
|
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
|
@ -207,6 +207,54 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 自定义选项上方内容
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-cascader
|
||||||
|
v-model="code"
|
||||||
|
title="请选择所在地区"
|
||||||
|
:options="options"
|
||||||
|
:field-names="fieldNames"
|
||||||
|
>
|
||||||
|
<template #options-top="{ activeTab }">
|
||||||
|
<span>当前为第{{ tabIndex }}级</span>
|
||||||
|
</template>
|
||||||
|
</van-cascader>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const code = ref('');
|
||||||
|
const fieldNames = {
|
||||||
|
text: 'name',
|
||||||
|
value: 'code',
|
||||||
|
children: 'items',
|
||||||
|
};
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
name: '浙江省',
|
||||||
|
code: '330000',
|
||||||
|
items: [{ name: '杭州市', code: '330100' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '江苏省',
|
||||||
|
code: '320000',
|
||||||
|
items: [{ name: '南京市', code: '320100' }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
code,
|
||||||
|
options,
|
||||||
|
fieldNames,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@ -248,9 +296,10 @@ export default {
|
|||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
| 名称 | 说明 | 参数 |
|
| 名称 | 说明 | 参数 |
|
||||||
| --------------- | -------------- | --------------------------------------- |
|
| --- | --- | --- |
|
||||||
| title | 自定义顶部标题 | - |
|
| title | 自定义顶部标题 | - |
|
||||||
| option `v3.1.4` | 自定义选项文字 | _{ option: Option, selected: boolean }_ |
|
| option `v3.1.4` | 自定义选项文字 | _{ option: Option, selected: boolean }_ |
|
||||||
|
| options-top | 自定义选项上方的内容 | - |
|
||||||
|
|
||||||
### 类型定义
|
### 类型定义
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ const t = useTranslate({
|
|||||||
{ text: '宁波市', value: '330200' },
|
{ text: '宁波市', value: '330200' },
|
||||||
],
|
],
|
||||||
customFieldNames: '自定义字段名',
|
customFieldNames: '自定义字段名',
|
||||||
|
customContent: '自定义内容',
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
area: 'Area',
|
area: 'Area',
|
||||||
@ -46,6 +47,7 @@ const t = useTranslate({
|
|||||||
{ text: 'Ningbo', value: '330200' },
|
{ text: 'Ningbo', value: '330200' },
|
||||||
],
|
],
|
||||||
customFieldNames: 'Custom Field Names',
|
customFieldNames: 'Custom Field Names',
|
||||||
|
customContent: 'Custom Content',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,6 +56,7 @@ type StateItem = {
|
|||||||
value: string | number | null;
|
value: string | number | null;
|
||||||
result: string;
|
result: string;
|
||||||
options?: CascaderOption[];
|
options?: CascaderOption[];
|
||||||
|
tabIndex?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const baseState = reactive<StateItem>({
|
const baseState = reactive<StateItem>({
|
||||||
@ -84,6 +87,12 @@ const fieldNames = {
|
|||||||
children: 'items',
|
children: 'items',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const customContentState = reactive<StateItem>({
|
||||||
|
show: false,
|
||||||
|
value: null,
|
||||||
|
result: '',
|
||||||
|
});
|
||||||
|
|
||||||
const customFieldOptions = computed(() => {
|
const customFieldOptions = computed(() => {
|
||||||
const options = deepClone(t('options'));
|
const options = deepClone(t('options'));
|
||||||
const adjustFieldName = (item: CascaderOption) => {
|
const adjustFieldName = (item: CascaderOption) => {
|
||||||
@ -234,4 +243,35 @@ const onFinish = (
|
|||||||
/>
|
/>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
|
<demo-block card :title="t('customContent')">
|
||||||
|
<van-field
|
||||||
|
v-model="customContentState.result"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
:label="t('area')"
|
||||||
|
:placeholder="t('selectArea')"
|
||||||
|
@click="customContentState.show = true"
|
||||||
|
/>
|
||||||
|
<van-popup
|
||||||
|
v-model:show="customContentState.show"
|
||||||
|
round
|
||||||
|
teleport="body"
|
||||||
|
position="bottom"
|
||||||
|
safe-area-inset-bottom
|
||||||
|
>
|
||||||
|
<van-cascader
|
||||||
|
v-model="customContentState.value"
|
||||||
|
:title="t('selectArea')"
|
||||||
|
:options="customFieldOptions"
|
||||||
|
:field-names="fieldNames"
|
||||||
|
@close="customContentState.show = false"
|
||||||
|
@finish="onFinish(customContentState, $event)"
|
||||||
|
>
|
||||||
|
<template #options-top="{ activeTab }">
|
||||||
|
<span>当前为第{{ activeTab }}级</span>
|
||||||
|
</template>
|
||||||
|
</van-cascader>
|
||||||
|
</van-popup>
|
||||||
|
</demo-block>
|
||||||
</template>
|
</template>
|
||||||
|
@ -241,3 +241,23 @@ test('should allow to custom the color of option', async () => {
|
|||||||
const option = wrapper.find('.van-cascader__option');
|
const option = wrapper.find('.van-cascader__option');
|
||||||
expect(option.style.color).toEqual('red');
|
expect(option.style.color).toEqual('red');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(' should allow more custom content', async () => {
|
||||||
|
const wrapper = mount(Cascader, {
|
||||||
|
slots: {
|
||||||
|
'options-top': ({ activeTab }) => activeTab,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await later();
|
||||||
|
wrapper
|
||||||
|
.findAll('.van-cascader__options')[0]
|
||||||
|
.find('.van-cascader__option')
|
||||||
|
.trigger('click');
|
||||||
|
wrapper.vm.$nextTick(() => {
|
||||||
|
const top = wrapper.find('.van-tab__pane');
|
||||||
|
expect(top.text()).toBe('1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user