diff --git a/src/cascader/__test__/__snapshots__/demo.test.jsx.snap b/src/cascader/__test__/__snapshots__/demo.test.jsx.snap index 66973064b..59b9f200e 100644 --- a/src/cascader/__test__/__snapshots__/demo.test.jsx.snap +++ b/src/cascader/__test__/__snapshots__/demo.test.jsx.snap @@ -2073,6 +2073,246 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = ` + + +
+
+ +

+ 选择任意一项 +

+
+
+ + +
+
+ + +
+
+ 地址 + + +
+
+ 请选择地址 +
+
+
+ + + +
+
+
+ + + diff --git a/src/cascader/cascader.en-US.md b/src/cascader/cascader.en-US.md index 5fe0241e8..4a1bff3ac 100644 --- a/src/cascader/cascader.en-US.md +++ b/src/cascader/cascader.en-US.md @@ -15,6 +15,7 @@ title | String / Slot / Function | - | Typescript:`string \| TNode`。[see mor value | String / Number | - | `v-model` and `v-model:value` is supported | N defaultValue | String / Number | - | uncontrolled property | N visible | Boolean | false | \- | N +checkStrictly | Boolean | false | 父子节点选中状态不再关联,可各自选中或取消 | N placeholder | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N onChange | Function | | Typescript:`(value: string \| number, selectedOptions: string[]) => void`
| N onClose | Function | | Typescript:`(trigger: TriggerSource) => void`
[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。
`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`
| N diff --git a/src/cascader/cascader.md b/src/cascader/cascader.md index a1909c90a..571d66189 100644 --- a/src/cascader/cascader.md +++ b/src/cascader/cascader.md @@ -14,6 +14,7 @@ title | String / Slot / Function | - | 标题。TS 类型:`string \| TNode`。 value | String / Number | - | 选项值。支持语法糖 `v-model` 或 `v-model:value` | N defaultValue | String / Number | - | 选项值。非受控属性 | N visible | Boolean | false | 是否展示 | N +checkStrictly | Boolean | false | 父子节点选中状态不再关联,可各自选中或取消 | N placeholder | String / Slot / Function | 选择选项 | 未选中时的提示文案。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N onChange | Function | | TS 类型:`(value: string \| number, selectedOptions: string[]) => void`
值发生变更时触发 | N onClose | Function | | TS 类型:`(trigger: TriggerSource) => void`
关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。
`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`
| N diff --git a/src/cascader/cascader.vue b/src/cascader/cascader.vue index dfd08b851..06a9c1193 100644 --- a/src/cascader/cascader.vue +++ b/src/cascader/cascader.vue @@ -5,7 +5,7 @@
-
+
@@ -55,7 +55,7 @@
props.title || '标题'); @@ -203,23 +203,13 @@ export default defineComponent({ } }; - const handleSelect = (e: string | number, level: number) => { - const value = e; - const index = items[level].findIndex( - (item: any) => item[(keys as Ref).value?.value ?? 'value'] === value, - ); - const item = items[level][index]; + const chooseSelect = (e: string | number, level: number, index: number, item: any) => { selectedIndexes[level] = index; selectedIndexes.length = level + 1; selectedValue[level] = String(e); selectedValue.length = level + 1; steps[level] = item[(keys as Ref).value?.label ?? 'label'] as string; - if (item.disabled) { - return; - } - props.onPick?.({ level, value: item[(keys as Ref).value?.value ?? 'value'], index }); - if (item[(keys as Ref).value?.children ?? 'children']?.length) { items[level + 1] = item[(keys as Ref).value?.children ?? 'children']; items.length = level + 2; @@ -238,6 +228,40 @@ export default defineComponent({ } }; + const cancelSelect = (e: string | number, level: number, index: number, item: any) => { + selectedIndexes[level] = index; + selectedIndexes.length = level; + selectedValue.length = level; + steps[level] = String(placeholder.value); + steps[level + 1] = placeholder.value; + steps.length = level + 1; + + if (item[(keys as Ref).value?.children ?? 'children']?.length) { + items[level + 1] = item[(keys as Ref).value?.children ?? 'children']; + } else if (item[(keys as Ref).value?.children ?? 'children']?.length === 0) { + childrenInfo.value = e; + childrenInfo.level = level; + } + }; + + const handleSelect = (e: string | number, level: number) => { + const value = e; + const index = items[level].findIndex( + (item: any) => item[(keys as Ref).value?.value ?? 'value'] === value, + ); + const item = items[level][index]; + if (item.disabled) { + return; + } + props.onPick?.({ level, value: item[(keys as Ref).value?.value ?? 'value'], index }); + + if (checkStrictly.value && selectedValue.includes(String(value))) { + cancelSelect(e, level, index, item); + } else { + chooseSelect(e, level, index, item); + } + }; + watch(open, () => { context.emit('update:visible', open.value); }); @@ -262,15 +286,34 @@ export default defineComponent({ props.onClose?.({ trigger }); }; - const onVisibleChange = (visible: boolean) => { + const onVisibleChange = (visible: boolean, e: any) => { + if (e?.trigger !== 'overlay') return; close('overlay'); }; + const updateCascaderValue = () => { + setCascaderValue( + selectedValue[selectedValue.length - 1], + items + .filter((item, index) => !!item && selectedIndexes.length > index) + .map((item, index) => toRaw(item?.[selectedIndexes[index]])), + ); + }; + const onClose = () => { open.value = false; close('close-btn'); }; + const onCloseBtn = () => { + if (checkStrictly.value) { + updateCascaderValue(); + onClose(); + } else { + onClose(); + } + }; + const onStepClick = (index: number) => { stepIndex.value = index; }; @@ -300,6 +343,7 @@ export default defineComponent({ items, setCascaderValue, onClose, + onCloseBtn, }; }, }); diff --git a/src/cascader/demos/check-strictly.vue b/src/cascader/demos/check-strictly.vue new file mode 100644 index 000000000..3f613cfa2 --- /dev/null +++ b/src/cascader/demos/check-strictly.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/cascader/demos/mobile.vue b/src/cascader/demos/mobile.vue index 29f2258fd..6c58ff60b 100644 --- a/src/cascader/demos/mobile.vue +++ b/src/cascader/demos/mobile.vue @@ -20,6 +20,9 @@ + + +
diff --git a/src/cascader/props.ts b/src/cascader/props.ts index 67c8f6354..dedacc5be 100644 --- a/src/cascader/props.ts +++ b/src/cascader/props.ts @@ -59,6 +59,11 @@ export default { }, /** 是否展示 */ visible: Boolean, + /** 父子节点选中状态不再关联,可各自选中或取消 */ + checkStrictly: { + type: Boolean, + default: false, + }, /** 值发生变更时触发 */ onChange: Function as PropType, /** 关闭时触发 */