feat(tree-select): add check-strategy prop (#758)

* feat(tree-select): 增加勾选指定中策略属性

* feat(tree-select): 更新日志

* feat(tree): update treemate to add check strategy

* feat(select): disabled option hide close iocn

* feat(tree): 兼容合并leaf-only与子策略属性

* feat: 回显值跟随策略优化

* feat: 优化回显结果

* Update TreeSelect.tsx

* Apply suggestions from code review

Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
小魔王 2021-09-03 01:16:57 +08:00 committed by GitHub
parent 29577a22d2
commit 6ccbe869c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 268 additions and 4 deletions

View File

@ -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).

View File

@ -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)

View File

@ -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
<n-tree-select
multiple
cascade
checkable
checkStrategy="parent"
:options="options"
:default-value="['Dig It', 'go']"
@update:value="updateValue"
/>
```
```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)
}
}
}
})
```

View File

@ -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. |

View File

@ -0,0 +1,119 @@
# 指定勾选策略
```html
<n-tree-select
multiple
cascade
checkable
check-strategy="parent"
:options="options"
:default-value="['Dig It', 'go']"
@update:value="updateValue"
/>
```
```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)
}
}
}
})
```

View File

@ -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` | 是否使菜单宽度和输入框一致,打开会禁用虚拟滚动 |

View File

@ -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<CheckStrategy>,
maxTagCount: [String, Number] as PropType<number | 'responsive'>,
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}

View File

@ -41,3 +41,5 @@ export interface TreeSelectInjection {
export const treeSelectInjectionKey: InjectionKey<TreeSelectInjection> =
Symbol('tree-select')
export type CheckStrategy = 'all' | 'parent' | 'child'

View File

@ -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<Key[]>,
checkStrategy: String as PropType<CheckStrategy>,
defaultCheckedKeys: {
type: Array as PropType<Key[]>,
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)
}