diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 6eae4c2578c..24dc953e6ba 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -112,6 +112,7 @@ ### Feats - `n-loading-bar` add `loading-bar-style` props, closes [#457](https://github.com/TuSimple/naive-ui/issues/457). +- `n-tree-select` add `check-strategy` prop. - `n-button` add `text-color` prop. - `n-form` export `FormValidationError` type. - `n-popconfirm` support not show action components, closes [#770](https://github.com/TuSimple/naive-ui/issues/770). diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index e789b99cfd1..1904a824c75 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -112,6 +112,7 @@ ### Feats - `n-loading-bar` 新增 `loading-bar-style` 属性,关闭 [#457](https://github.com/TuSimple/naive-ui/issues/457) +- `n-tree-select` 增加 `check-strategy` 属性. - `n-button` 新增 `text-color` 属性 - `n-form` 导出 `FormValidationError` 类型 - `n-popconfirm` 支持不显示操作组件,关闭 [#770](https://github.com/TuSimple/naive-ui/issues/770) diff --git a/src/tree-select/demos/enUS/check-strategy.demo.md b/src/tree-select/demos/enUS/check-strategy.demo.md new file mode 100644 index 00000000000..8cf1b18b56a --- /dev/null +++ b/src/tree-select/demos/enUS/check-strategy.demo.md @@ -0,0 +1,121 @@ +# Set Check Strategy + +# all: show all checked node; parent: show all checked parent node when all child node are checked; child: show all child node + +```html + +``` + +```js +import { defineComponent } from 'vue' + +export default defineComponent({ + setup () { + return { + options: [ + { + label: 'Rubber Soul', + key: 'Rubber Soul', + children: [ + { + label: + "Everybody's Got Something to Hide Except Me and My Monkey", + key: "Everybody's Got Something to Hide Except Me and My Monkey" + }, + { + label: 'Drive My Car', + key: 'Drive My Car', + disabled: true + }, + { + label: 'Norwegian Wood', + key: 'Norwegian Wood' + }, + { + label: "You Won't See", + key: "You Won't See", + disabled: true + }, + { + label: 'Nowhere Man', + key: 'Nowhere Man' + }, + { + label: 'Think For Yourself', + key: 'Think For Yourself' + }, + { + label: 'The Word', + key: 'The Word' + }, + { + label: 'Michelle', + key: 'Michelle', + disabled: true + }, + { + label: 'What goes on', + key: 'What goes on' + }, + { + label: 'Girl', + key: 'Girl' + }, + { + label: "I'm looking through you", + key: "I'm looking through you" + }, + { + label: 'In My Life', + key: 'In My Life' + }, + { + label: 'Wait', + key: 'Wait' + } + ] + }, + { + label: 'Let It Be', + key: 'Let It Be Album', + children: [ + { + label: 'Two Of Us', + key: 'Two Of Us' + }, + { + label: 'Dig A Pony', + key: 'Dig A Pony' + }, + { + label: 'Across The Universe', + key: 'Across The Universe', + children: [ + { + label: 'Dig It', + key: 'Dig It' + }, + { + label: 'go', + key: 'go' + } + ] + } + ] + } + ], + updateValue: (values) => { + console.log(values) + } + } + } +}) +``` diff --git a/src/tree-select/demos/enUS/index.demo-entry.md b/src/tree-select/demos/enUS/index.demo-entry.md index 198a9fb6c42..1e1db355b2e 100644 --- a/src/tree-select/demos/enUS/index.demo-entry.md +++ b/src/tree-select/demos/enUS/index.demo-entry.md @@ -9,6 +9,7 @@ basic custom-field multiple checkbox +check-strategy filterable debug ``` @@ -21,6 +22,7 @@ debug | --- | --- | --- | --- | | cascade | `boolean` | `false` | Whether to do cascade check when use checkboxes. | | checkable | `boolean` | `false` | Whether to use checkbox to select value. | +| check-strategy | `string` | `'all'` | The way to show checked options. `all`: Show all checked node. `parent`: Show all checked parent node when all child node are checked. `child`: show all child node. | | children-field | `string` | `'children'` | The children field in `TreeSelectOption`. | | clearable | `boolean` | `false` | Whether it's clearable. | | consistent-menu-width | `boolean` | `true` | Whether to make menu's width consistent with input. Set to `true` will disable virtual scroll. | diff --git a/src/tree-select/demos/zhCN/check-strategy.demo.md b/src/tree-select/demos/zhCN/check-strategy.demo.md new file mode 100644 index 00000000000..e93469b69d5 --- /dev/null +++ b/src/tree-select/demos/zhCN/check-strategy.demo.md @@ -0,0 +1,119 @@ +# 指定勾选策略 + +```html + +``` + +```js +import { defineComponent } from 'vue' + +export default defineComponent({ + setup () { + return { + options: [ + { + label: 'Rubber Soul', + key: 'Rubber Soul', + children: [ + { + label: + "Everybody's Got Something to Hide Except Me and My Monkey", + key: "Everybody's Got Something to Hide Except Me and My Monkey" + }, + { + label: 'Drive My Car', + key: 'Drive My Car', + disabled: true + }, + { + label: 'Norwegian Wood', + key: 'Norwegian Wood' + }, + { + label: "You Won't See", + key: "You Won't See", + disabled: true + }, + { + label: 'Nowhere Man', + key: 'Nowhere Man' + }, + { + label: 'Think For Yourself', + key: 'Think For Yourself' + }, + { + label: 'The Word', + key: 'The Word' + }, + { + label: 'Michelle', + key: 'Michelle', + disabled: true + }, + { + label: 'What goes on', + key: 'What goes on' + }, + { + label: 'Girl', + key: 'Girl' + }, + { + label: "I'm looking through you", + key: "I'm looking through you" + }, + { + label: 'In My Life', + key: 'In My Life' + }, + { + label: 'Wait', + key: 'Wait' + } + ] + }, + { + label: 'Let It Be', + key: 'Let It Be Album', + children: [ + { + label: 'Two Of Us', + key: 'Two Of Us' + }, + { + label: 'Dig A Pony', + key: 'Dig A Pony' + }, + { + label: 'Across The Universe', + key: 'Across The Universe', + children: [ + { + label: 'Dig It', + key: 'Dig It' + }, + { + label: 'go', + key: 'go' + } + ] + } + ] + } + ], + updateValue: (values) => { + console.log(values) + } + } + } +}) +``` diff --git a/src/tree-select/demos/zhCN/index.demo-entry.md b/src/tree-select/demos/zhCN/index.demo-entry.md index dd2b1e2d0b2..0151c2ac760 100644 --- a/src/tree-select/demos/zhCN/index.demo-entry.md +++ b/src/tree-select/demos/zhCN/index.demo-entry.md @@ -9,6 +9,7 @@ basic custom-field multiple checkbox +check-strategy filterable debug ``` @@ -21,6 +22,7 @@ debug | --- | --- | --- | --- | | cascade | `boolean` | `false` | 使用 checkbox 进行多选时是否级联 | | checkable | `boolean` | `false` | 是否使用 checkbox 进行选择 | +| check-strategy | `string` | `'all'` | 设置勾选策略来指定显示的勾选节点,`all`:显示全部选中节点;`parent`:只显示父节点(当父节点下所有子节点都选中时);`child`:只显示子节点 | | children-field | `string` | `'children'` | 替代 `TreeSelectOption` 中的 children 字段名 | | clearable | `boolean` | `false` | 是否可清除 | | consistent-menu-width | `boolean` | `true` | 是否使菜单宽度和输入框一致,打开会禁用虚拟滚动 | diff --git a/src/tree-select/src/TreeSelect.tsx b/src/tree-select/src/TreeSelect.tsx index 1721a572316..d70984c88e4 100644 --- a/src/tree-select/src/TreeSelect.tsx +++ b/src/tree-select/src/TreeSelect.tsx @@ -47,7 +47,7 @@ import type { TreeSelectOption, Value } from './interface' -import { treeSelectInjectionKey } from './interface' +import { treeSelectInjectionKey, CheckStrategy } from './interface' import { treeOption2SelectOption, filterTree, @@ -81,6 +81,7 @@ const props = { }, filterable: Boolean, leafOnly: Boolean, + checkStrategy: String as PropType, maxTagCount: [String, Number] as PropType, multiple: Boolean, showPath: Boolean, @@ -285,11 +286,17 @@ export default defineComponent({ if (Array.isArray(mergedValue)) { const res: SelectBaseOption[] = [] const { value: treeMate } = dataTreeMateRef + const { checkedKeys } = treeMate.getCheckedKeys(mergedValue) const { keyField, labelField } = props - mergedValue.forEach((value) => { + checkedKeys.forEach((value) => { const tmNode = treeMate.getNode(value) if (tmNode !== null) { - res.push( + if ( + props.checkStrategy === 'all' || + (props.checkStrategy === 'parent' && !tmNode.isLeaf) || + (props.checkStrategy === 'child' && tmNode.isLeaf) + ) { + res.push( showPath ? treeOption2SelectOptionWithPath( tmNode, @@ -299,6 +306,7 @@ export default defineComponent({ ) : treeOption2SelectOption(tmNode, labelField) ) + } } }) return res @@ -691,6 +699,7 @@ export default defineComponent({ mergedClsPrefix, filteredTreeInfo, checkable, + checkStrategy, multiple } = this return withDirectives( @@ -723,6 +732,7 @@ export default defineComponent({ checkedKeys={this.treeCheckedKeys} selectedKeys={this.treeSelectedKeys} checkable={checkable} + checkStrategy={checkStrategy} cascade={this.mergedCascade} leafOnly={this.leafOnly} multiple={this.multiple} diff --git a/src/tree-select/src/interface.ts b/src/tree-select/src/interface.ts index d2f53b85f36..034654ed84d 100644 --- a/src/tree-select/src/interface.ts +++ b/src/tree-select/src/interface.ts @@ -41,3 +41,5 @@ export interface TreeSelectInjection { export const treeSelectInjectionKey: InjectionKey = Symbol('tree-select') + +export type CheckStrategy = 'all' | 'parent' | 'child' diff --git a/src/tree/src/Tree.tsx b/src/tree/src/Tree.tsx index ae3be5f904c..dad68349180 100644 --- a/src/tree/src/Tree.tsx +++ b/src/tree/src/Tree.tsx @@ -28,6 +28,7 @@ import { call, createDataKey, warn } from '../../_utils' import type { ExtractPublicPropTypes, MaybeArray } from '../../_utils' import { NxScrollbar } from '../../scrollbar' import type { ScrollbarInst } from '../../scrollbar' +import { CheckStrategy } from '../../tree-select/src/interface' import { treeLight } from '../styles' import type { TreeTheme } from '../styles' import NTreeNode from './TreeNode' @@ -126,6 +127,7 @@ const treeProps = { blockLine: Boolean, disabled: Boolean, checkedKeys: Array as PropType, + checkStrategy: String as PropType, defaultCheckedKeys: { type: Array as PropType, default: () => [] @@ -263,6 +265,9 @@ export default defineComponent({ cascade: props.cascade }) }) + const mergedCheckStrategyRef = computed(() => + props.leafOnly ? 'child' : props.checkStrategy + ) const displayedCheckedKeysRef = computed(() => { return checkedStatusRef.value.checkedKeys }) @@ -567,7 +572,8 @@ export default defineComponent({ checked ? 'check' : 'uncheck' ](node.key, displayedCheckedKeysRef.value, { cascade: props.cascade, - leafOnly: props.leafOnly + leafOnly: props.leafOnly, + checkStrategy: mergedCheckStrategyRef.value }) doUpdateCheckedKeys(checkedKeys) }