From 7ec0f3a4426ae0941b287cd58e7556b9bbf26b9d Mon Sep 17 00:00:00 2001 From: snowbitx <109521682+snowbitx@users.noreply.github.com> Date: Tue, 22 Jul 2025 17:23:20 +0800 Subject: [PATCH] feat(components): [cascader] add `checkOnClickNode` and `prefix` prop (#21089) * feat(components): [cascader] Hide radio in single mode * feat(components): [cascader] Renamed prop to \`selectOnClick\` * feat(components): [cascader] Update doc * feat(components): [cascader] Adjust how data is fetched * feat(components): [cascader] update type * Update packages/components/cascader-panel/src/node-content.ts Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * feat(components): [cascader] Merge and fix v-model bug * feat(components): [cascader] Renamed to checkOnClickNode * feat(components): [cascader] Renamed to checkOnClickNode * feat(components): [cascader] merge * feat(components): [cascader] Add a check * feat(components): [cascader] Add test case * feat(components): [cascader] Fix type error * feat(components): [cascader] Add checkOnClickNode, showRadio props * feat(components): [cascader] Update doc * Update packages/components/cascader/src/cascader.ts Done, thanks! Co-authored-by: btea <2356281422@qq.com> * fix: showRadio defaults checkOnClickNode * test: showRadio fallback behavior * refactor: rename prop and support checkOnClickNode for multiple mode * doc:update * Update packages/components/cascader-panel/src/config.ts Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * docs: tweak props * docs: update doc * chore: update doc & fix toggle check * Update docs/en-US/component/cascader.md Co-authored-by: btea <2356281422@qq.com> * Update docs/en-US/component/cascader.md Co-authored-by: btea <2356281422@qq.com> * Update docs/en-US/component/cascader.md Co-authored-by: btea <2356281422@qq.com> * Update cascader-panel.test.tsx --------- Co-authored-by: WANGXIAOYU1995 <109521682+WANGXIAOYU1995@users.noreply.github.com> Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> Co-authored-by: btea <2356281422@qq.com> Co-authored-by: Dsaquel <291874700n@gmail.com> --- docs/en-US/component/cascader.md | 40 ++- .../examples/cascader/check-on-click-node.vue | 309 ++++++++++++++++++ .../components/cascader-panel/src/config.ts | 8 + .../cascader-panel/src/node-content.tsx | 17 +- .../components/cascader-panel/src/node.ts | 2 + .../components/cascader-panel/src/node.vue | 16 +- .../cascader/__tests__/cascader.test.tsx | 61 ++++ packages/components/cascader/src/cascader.ts | 11 + packages/components/select/src/option.vue | 6 +- 9 files changed, 447 insertions(+), 23 deletions(-) create mode 100644 docs/examples/cascader/check-on-click-node.vue diff --git a/docs/en-US/component/cascader.md b/docs/en-US/component/cascader.md index f6c53fb9db..3561c3f12f 100644 --- a/docs/en-US/component/cascader.md +++ b/docs/en-US/component/cascader.md @@ -148,6 +148,16 @@ cascader/custom-tag ::: +## Click to Select Node ^(2.10.5) + +Allows selecting nodes by clicking, with optional control visibility. + +:::demo Select nodes on click via `checkOnClickNode`. You can also hide the selection control with `showPrefix`. + +cascader/check-on-click-node + +::: + ## Cascader API ### Cascader Attributes @@ -250,20 +260,22 @@ cascader/custom-tag ## CascaderProps -| Attribute | Description | Type | Default | -| -------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -------- | -| expandTrigger | trigger mode of expanding options | ^[enum]`'click' \| 'hover'` | click | -| multiple | whether multiple selection is enabled | ^[boolean] | false | -| checkStrictly | whether checked state of a node not affects its parent and child nodes | ^[boolean] | false | -| emitPath | when checked nodes change, whether to emit an array of node's path, if false, only emit the value of node. | ^[boolean] | true | -| lazy | whether to dynamic load child nodes, use with `lazyload` attribute | ^[boolean] | false | -| lazyLoad | method for loading child nodes data, only works when `lazy` is true | ^[Function]`(node: Node, resolve: Resolve) => void` | — | -| value | specify which key of node object is used as the node's value | ^[string] | value | -| label | specify which key of node object is used as the node's label | ^[string] | label | -| children | specify which key of node object is used as the node's children | ^[string] | children | -| disabled | specify which key of node object is used as the node's disabled | ^[string] | disabled | -| leaf | specify which key of node object is used as the node's leaf field | ^[string] | leaf | -| hoverThreshold | hover threshold of expanding options | ^[number] | 500 | +| Attribute | Description | Type | Default | +| -------------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | -------- | +| expandTrigger | trigger mode of expanding options | ^[enum]`'click' \| 'hover'` | click | +| multiple | whether multiple selection is enabled | ^[boolean] | false | +| checkStrictly | whether checked state of a node not affects its parent and child nodes | ^[boolean] | false | +| emitPath | when checked nodes change, whether to emit an array of node's path, if false, only emit the value of node. | ^[boolean] | true | +| lazy | whether to dynamic load child nodes, use with `lazyload` attribute | ^[boolean] | false | +| lazyLoad | method for loading child nodes data, only works when `lazy` is true | ^[Function]`(node: Node, resolve: Resolve) => void` | — | +| value | specify which key of node object is used as the node's value | ^[string] | value | +| label | specify which key of node object is used as the node's label | ^[string] | label | +| children | specify which key of node object is used as the node's children | ^[string] | children | +| disabled | specify which key of node object is used as the node's disabled | ^[string] | disabled | +| leaf | specify which key of node object is used as the node's leaf field | ^[string] | leaf | +| hoverThreshold | hover threshold of expanding options | ^[number] | 500 | +| checkOnClickNode ^(2.10.5) | whether to check or uncheck node when clicking on the node | ^[boolean] | false | +| showPrefix ^(2.10.5) | whether to show the radio or checkbox prefix | ^[boolean] | true | ## Type Declarations diff --git a/docs/examples/cascader/check-on-click-node.vue b/docs/examples/cascader/check-on-click-node.vue new file mode 100644 index 0000000000..e8e1b84bf7 --- /dev/null +++ b/docs/examples/cascader/check-on-click-node.vue @@ -0,0 +1,309 @@ + + + diff --git a/packages/components/cascader-panel/src/config.ts b/packages/components/cascader-panel/src/config.ts index c77007553a..da147f72cb 100644 --- a/packages/components/cascader-panel/src/config.ts +++ b/packages/components/cascader-panel/src/config.ts @@ -84,6 +84,14 @@ export const DefaultProps: CascaderConfig = { * @description hover threshold of expanding options */ hoverThreshold: 500, + /** + * @description whether to check or uncheck node when clicking on the node + */ + checkOnClickNode: false, + /** + * @description whether to show the radio or checkbox prefix + */ + showPrefix: true, } export const cascaderPanelProps = buildProps({ diff --git a/packages/components/cascader-panel/src/node-content.tsx b/packages/components/cascader-panel/src/node-content.tsx index 6acb72e130..3ef459bbc9 100644 --- a/packages/components/cascader-panel/src/node-content.tsx +++ b/packages/components/cascader-panel/src/node-content.tsx @@ -19,17 +19,26 @@ export default defineComponent({ required: true, }, renderLabelFn: Function as PropType, + checkOnClickNode: Boolean, + disabled: Boolean, }, - setup(props) { + setup(props, { emit }) { const ns = useNamespace('cascader-node') - const { renderLabelFn, node } = props + const { renderLabelFn, node, disabled, checkOnClickNode } = props const { data, label: nodeLabel } = node const label = () => { const renderLabel = renderLabelFn?.({ node, data }) return isVNodeEmpty(renderLabel) ? nodeLabel : renderLabel ?? nodeLabel } - - return () => {label()} + function handleClick() { + if (disabled || !checkOnClickNode) return + emit('handleSelectCheck', !node.checked) + } + return () => ( + + {label()} + + ) }, }) diff --git a/packages/components/cascader-panel/src/node.ts b/packages/components/cascader-panel/src/node.ts index e11e43b967..eb59ba3ae0 100644 --- a/packages/components/cascader-panel/src/node.ts +++ b/packages/components/cascader-panel/src/node.ts @@ -40,6 +40,8 @@ export interface CascaderProps { disabled?: string | isDisabled leaf?: string | isLeaf hoverThreshold?: number + checkOnClickNode?: boolean + showPrefix?: boolean } export type Nullable = null | T diff --git a/packages/components/cascader-panel/src/node.vue b/packages/components/cascader-panel/src/node.vue index 015e56f0a3..7293e38f34 100644 --- a/packages/components/cascader-panel/src/node.vue +++ b/packages/components/cascader-panel/src/node.vue @@ -20,7 +20,7 @@ > - - + +