Skip to content

Commit

Permalink
feat(cascader): cascader支持checkStrictly (#1192)
Browse files Browse the repository at this point in the history
* feat(cascader): cascader support check-strictly

* fix(Cascader): resolved the problem of triggering close event on first click

* feat(Cascader): support cancel select

* fix(Cascader): fix cr

* feat(cascader): cascader

---------

Co-authored-by: anlyyao <[email protected]>
  • Loading branch information
LoopZhou and anlyyao authored Dec 22, 2023
1 parent dc42573 commit 1286f1b
Show file tree
Hide file tree
Showing 7 changed files with 414 additions and 15 deletions.
240 changes: 240 additions & 0 deletions src/cascader/__test__/__snapshots__/demo.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2073,6 +2073,246 @@ exports[`Cascader > Cascader mobileVue demo works fine 1`] = `
</teleport-stub>
</div>
</div>
<div
class="tdesign-mobile-demo-block tdesign-mobile-demo-block_notitle"
>
<div
class="tdesign-mobile-demo-block__header"
>
<!--v-if-->
<p
class="tdesign-mobile-demo-block__summary tdesign-mobile-demo-block_subtitle"
>
选择任意一项
</p>
</div>
<div
class="tdesign-mobile-demo-block__slot"
>
<div
class="t-cell t-cell--middle"
data-v-e4157e3c=""
>
<div
class="t-cell__left"
>
<!--v-if-->
<!---->
</div>
<div
class="t-cell__title"
>
地址
<!--v-if-->
<!--v-if-->
</div>
<div
class="t-cell__note"
>
请选择地址
</div>
<div
class="t-cell__right"
>
<div
class="t-cell__right-icon"
>
<svg
class="t-icon t-icon-chevron-right"
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
>
<path
d="M8.09 17.5l5.5-5.5-5.5-5.5L9.5 5.09 16.41 12 9.5 18.91 8.09 17.5z"
fill="currentColor"
/>
</svg>
</div>
</div>
</div>
<teleport-stub
data-v-e4157e3c=""
disabled="false"
to="[object HTMLBodyElement]"
>
<div
class="t-overlay"
style="z-index: 1000; transition-duration: 300ms; display: none;"
>
</div>
<div
class="t-popup t-popup--bottom"
style="display: none;"
>
<!--v-if-->
<div
class="t-cascader"
>
<div
class="t-cascader__title"
>
选择地址
</div>
<div
class="t-cascader__close-btn"
>
<span
class="confirm-btn"
data-v-e4157e3c=""
>
确定
</span>
</div>
<div
class="t-cascader__content"
>
<div>
<div
class="t-cascader__steps"
>
<div
class="t-cascader__step"
>
<div
class="t-cascader__step-dot t-cascader__step-dot--last"
/>
<div
class="t-cascader__step-label t-cascader__step-label--active"
>
选择选项
</div>
<svg
class="t-icon t-icon-chevron-right t-cascader__step-arrow"
fill="none"
height="1em"
viewBox="0 0 24 24"
width="1em"
>
<path
d="M8.09 17.5l5.5-5.5-5.5-5.5L9.5 5.09 16.41 12 9.5 18.91 8.09 17.5z"
fill="currentColor"
/>
</svg>
</div>
</div>
<!--v-if-->
</div>
<!--v-if-->
<div
class="t-cascader__options-container"
style="width: 200vw; transform: translateX(-000vw);"
>
<div
class="t-cascader__options"
>
<div
class="cascader-radio-group-0 slide-enter-from slide-enter-active"
>
<div
class="t-radio-group"
role="radiogroup"
>
<div
class="t-radio t-radio--right t-radio--block"
>
<input
class="t-radio__original"
name=""
type="radio"
value="110000"
/>
<div
class="t-radio__icon t-radio__icon--right"
>
<!--v-if-->
<!--v-if-->
<!--v-if-->
<!--v-if-->
<div
class="placeholder"
/>
<!---->
</div>
<div
class="t-radio__content"
>
<span
class="t-radio__title"
style=""
>
北京市
</span>
<!--v-if-->
</div>
<!--v-if-->
</div>
<div
class="t-radio t-radio--right t-radio--block"
>
<input
class="t-radio__original"
name=""
type="radio"
value="120000"
/>
<div
class="t-radio__icon t-radio__icon--right"
>
<!--v-if-->
<!--v-if-->
<!--v-if-->
<!--v-if-->
<div
class="placeholder"
/>
<!---->
</div>
<div
class="t-radio__content"
>
<span
class="t-radio__title"
style=""
>
天津市
</span>
<!--v-if-->
</div>
<!--v-if-->
</div>
<!--v-if-->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</teleport-stub>
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/cascader/cascader.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`<br/> | N
onClose | Function | | Typescript:`(trigger: TriggerSource) => void`<br/>[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`<br/> | N
Expand Down
1 change: 1 addition & 0 deletions src/cascader/cascader.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`<br/>值发生变更时触发 | N
onClose | Function | | TS 类型:`(trigger: TriggerSource) => void`<br/>关闭时触发。[详细类型定义](https://github.com/Tencent/tdesign-mobile-vue/tree/develop/src/cascader/type.ts)。<br/>`type TriggerSource = 'overlay' \| 'close-btn' \| 'finish'`<br/> | N
Expand Down
74 changes: 59 additions & 15 deletions src/cascader/cascader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<t-node v-if="!(typeof titleTNode === 'string')" :content="titleTNode" />
<template v-else>{{ title }}</template>
</div>
<div :class="`${name}__close-btn`" @click="onClose">
<div :class="`${name}__close-btn`" @click="onCloseBtn">
<t-node v-if="closeBtnTNode" :content="closeBtnTNode" />
</div>
<div :class="`${name}__content`">
Expand Down Expand Up @@ -55,7 +55,7 @@
<transition appear name="slide">
<div :class="`cascader-radio-group-${index}`">
<t-radio-group
:value="selectedValue[index]"
:value="selectedValue[index] || ''"
:keys="keys"
:options="options"
placement="right"
Expand Down Expand Up @@ -127,7 +127,7 @@ export default defineComponent({
props: TdCascaderProps,
emits: ['change', 'close', 'pick', 'update:modelValue', 'update:value', 'update:visible'],
setup(props, context) {
const { visible, value, modelValue, subTitles, options, keys } = toRefs(props);
const { visible, value, modelValue, subTitles, options, keys, checkStrictly } = toRefs(props);
const open = ref(visible.value || false);
const [cascaderValue, setCascaderValue] = useVModel(value, modelValue, props.defaultValue, props.onChange);
const title = computed(() => props.title || '标题');
Expand Down Expand Up @@ -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<KeysType>).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<KeysType>).value?.label ?? 'label'] as string;
if (item.disabled) {
return;
}
props.onPick?.({ level, value: item[(keys as Ref<KeysType>).value?.value ?? 'value'], index });
if (item[(keys as Ref<KeysType>).value?.children ?? 'children']?.length) {
items[level + 1] = item[(keys as Ref<KeysType>).value?.children ?? 'children'];
items.length = level + 2;
Expand All @@ -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<KeysType>).value?.children ?? 'children']?.length) {
items[level + 1] = item[(keys as Ref<KeysType>).value?.children ?? 'children'];
} else if (item[(keys as Ref<KeysType>).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<KeysType>).value?.value ?? 'value'] === value,
);
const item = items[level][index];
if (item.disabled) {
return;
}
props.onPick?.({ level, value: item[(keys as Ref<KeysType>).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);
});
Expand All @@ -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;
};
Expand Down Expand Up @@ -300,6 +343,7 @@ export default defineComponent({
items,
setCascaderValue,
onClose,
onCloseBtn,
};
},
});
Expand Down
Loading

0 comments on commit 1286f1b

Please sign in to comment.