feat(tree, tree-select): add nodeKey prop (#998)

* feat(tree,tree-select): add nodeKey prop

* fix code

* docs: format
This commit is contained in:
kalykun 2021-08-30 01:01:25 +08:00 committed by GitHub
parent ed43daf9c4
commit 5f26ecf0e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 39 additions and 10 deletions

View File

@ -7,6 +7,7 @@
- `n-cascader` add `onUpdateValue` prop. - `n-cascader` add `onUpdateValue` prop.
- `n-auto-complete` add `onUpdateValue` prop. - `n-auto-complete` add `onUpdateValue` prop.
- `n-data-table`'s column's `renderFilterMenu` add `hide` params. - `n-data-table`'s column's `renderFilterMenu` add `hide` params.
- `n-tree` & `n-tree-select` add `node-key` prop.
### Fixes ### Fixes

View File

@ -7,6 +7,7 @@
- `n-cascader` 新增 `onUpdateValue` 方法 - `n-cascader` 新增 `onUpdateValue` 方法
- `n-auto-complete` 新增 `onUpdateValue` 方法 - `n-auto-complete` 新增 `onUpdateValue` 方法
- `n-data-table` 的列的 `renderFilterMenu` 新增 hide 参数 - `n-data-table` 的列的 `renderFilterMenu` 新增 hide 参数
- `n-tree``n-tree-select` 新增 `node-key` 属性
### Fixes ### Fixes

View File

@ -31,6 +31,7 @@ debug
| filter | `(pattern: string, option: TreeSelectOption) => boolean` | - | Filter function. | | filter | `(pattern: string, option: TreeSelectOption) => boolean` | - | Filter function. |
| max-tag-count | `number \| 'responsive'` | `undefined` | Max tag count to be shown in multiple mode. Set to `'responsive'` will keep all tags in the same row. | | max-tag-count | `number \| 'responsive'` | `undefined` | Max tag count to be shown in multiple mode. Set to `'responsive'` will keep all tags in the same row. |
| multiple | `boolean` | `false` | Whether to support multiple select. | | multiple | `boolean` | `false` | Whether to support multiple select. |
| node-key | `string` | `undefined` | Replace the key in `TreeSelectOption`. |
| options | `TreeSelectOption[]` | `[]` | Options. | | options | `TreeSelectOption[]` | `[]` | Options. |
| placeholder | `string` | `'Please Select'` | Placeholder. | | placeholder | `string` | `'Please Select'` | Placeholder. |
| separator | `string` | `' / '` | Option value separator. | | separator | `string` | `' / '` | Option value separator. |

View File

@ -32,6 +32,7 @@ debug
| leaf-only | `boolean` | `false` | 是否开启仅末层树节点可选 | | leaf-only | `boolean` | `false` | 是否开启仅末层树节点可选 |
| max-tag-count | `number \| 'responsive'` | `undefined` | 多选时最多直接显示多少选项,设为 `'responsive'` 会保证最多一行 | | max-tag-count | `number \| 'responsive'` | `undefined` | 多选时最多直接显示多少选项,设为 `'responsive'` 会保证最多一行 |
| multiple | `boolean` | `false` | 是否支持多选 | | multiple | `boolean` | `false` | 是否支持多选 |
| node-key | `string` | `undefined` | 替代 `TreeSelectOption` 中的 key |
| options | `TreeSelectOption[]` | `[]` | 选项 | | options | `TreeSelectOption[]` | `[]` | 选项 |
| placeholder | `string` | `'请选择'` | 占位信息 | | placeholder | `string` | `'请选择'` | 占位信息 |
| separator | `string` | `' / '` | 数据分隔符 | | separator | `string` | `' / '` | 数据分隔符 |

View File

@ -24,7 +24,7 @@ import { clickoutside } from 'vdirs'
import { createTreeMate } from 'treemate' import { createTreeMate } from 'treemate'
import { Key, InternalTreeInst } from '../../tree/src/interface' import { Key, InternalTreeInst } from '../../tree/src/interface'
import type { SelectBaseOption } from '../../select/src/interface' import type { SelectBaseOption } from '../../select/src/interface'
import { treeMateOptions, treeSharedProps } from '../../tree/src/Tree' import { createTreeMateOptions, treeSharedProps } from '../../tree/src/Tree'
import { import {
NInternalSelection, NInternalSelection,
InternalSelectionInst, InternalSelectionInst,
@ -61,6 +61,7 @@ const props = {
type: Boolean, type: Boolean,
default: true default: true
}, },
nodeKey: String,
cascade: Boolean, cascade: Boolean,
checkable: Boolean, checkable: Boolean,
clearable: Boolean, clearable: Boolean,
@ -177,12 +178,15 @@ export default defineComponent({
}) })
// used to resolve selected options // used to resolve selected options
const dataTreeMateRef = computed(() => const dataTreeMateRef = computed(() =>
createTreeMate<TreeSelectOption>(props.options, treeMateOptions) createTreeMate<TreeSelectOption>(
props.options,
createTreeMateOptions(props.nodeKey)
)
) )
const displayTreeMateRef = computed(() => const displayTreeMateRef = computed(() =>
createTreeMate<TreeSelectOption>( createTreeMate<TreeSelectOption>(
filteredTreeInfoRef.value.filteredTree, filteredTreeInfoRef.value.filteredTree,
treeMateOptions createTreeMateOptions(props.nodeKey)
) )
) )
const { value: initMergedValue } = mergedValueRef const { value: initMergedValue } = mergedValueRef

View File

@ -8,7 +8,7 @@ export function treeOption2SelectOption (
const { rawNode } = tmNode const { rawNode } = tmNode
return { return {
...rawNode, ...rawNode,
value: rawNode.key value: tmNode.key
} }
} }
@ -20,7 +20,7 @@ export function treeOption2SelectOptionWithPath (
const { rawNode } = tmNode const { rawNode } = tmNode
return { return {
...rawNode, ...rawNode,
value: rawNode.key, value: tmNode.key,
label: path.map((v) => v.rawNode.label).join(separator) label: path.map((v) => v.rawNode.label).join(separator)
} }
} }

View File

@ -43,6 +43,7 @@ batch-render
| filter | `(node: TreeOption) => boolean` | `undefined` | A simple string based filter. | | filter | `(node: TreeOption) => boolean` | `undefined` | A simple string based filter. |
| leaf-only | `boolean` | `false` | Whether to open or not, only the bottom tree node is optional. | | leaf-only | `boolean` | `false` | Whether to open or not, only the bottom tree node is optional. |
| multiple | `boolean` | `false` | Whether to allow multiple selection of nodes. | | multiple | `boolean` | `false` | Whether to allow multiple selection of nodes. |
| node-key | `string` | `undefined` | Replace the key in `TreeOption`. |
| on-load | `(node: TreeOption) => Promise<void>` | `undefined` | Callback function for asynchronously loading data. | | on-load | `(node: TreeOption) => Promise<void>` | `undefined` | Callback function for asynchronously loading data. |
| pattern | `string` | `''` | What to search by default. | | pattern | `string` | `''` | What to search by default. |
| remote | `boolean` | `false` | Whether to load nodes async. It should work with `on-load`. | | remote | `boolean` | `false` | Whether to load nodes async. It should work with `on-load`. |

View File

@ -43,6 +43,7 @@ batch-render
| filter | `(node: TreeOption) => boolean` | `undefined` | 一个简单的字符串过滤算法 | | filter | `(node: TreeOption) => boolean` | `undefined` | 一个简单的字符串过滤算法 |
| leaf-only | `boolean` | `false` | 是否开启仅末层树节点可选 | | leaf-only | `boolean` | `false` | 是否开启仅末层树节点可选 |
| multiple | `boolean` | `false` | 是否允许节点多选 | | multiple | `boolean` | `false` | 是否允许节点多选 |
| node-key | `string` | `undefined` | 替代 `TreeOption` 中的 key |
| on-load | `(node: TreeOption) => Promise<void>` | `undefined` | 异步加载数据的回调函数 | | on-load | `(node: TreeOption) => Promise<void>` | `undefined` | 异步加载数据的回调函数 |
| pattern | `string` | `''` | 默认搜索的内容 | | pattern | `string` | `''` | 默认搜索的内容 |
| remote | `boolean` | `false` | 是否异步获取选项,和 `onLoad` 配合 | | remote | `boolean` | `false` | 是否异步获取选项,和 `onLoad` 配合 |

View File

@ -12,7 +12,13 @@ import {
VNode, VNode,
nextTick nextTick
} from 'vue' } from 'vue'
import { createTreeMate, flatten, createIndexGetter, TreeMate } from 'treemate' import {
createTreeMate,
flatten,
createIndexGetter,
TreeMate,
TreeMateOptions
} from 'treemate'
import { useMergedState } from 'vooks' import { useMergedState } from 'vooks'
import { VirtualListInst, VVirtualList } from 'vueuc' import { VirtualListInst, VVirtualList } from 'vueuc'
import { getPadding } from 'seemly' import { getPadding } from 'seemly'
@ -55,9 +61,16 @@ import style from './styles/index.cssr'
const ITEM_SIZE = 30 // 24 + 3 + 3 const ITEM_SIZE = 30 // 24 + 3 + 3
export const treeMateOptions = { export function createTreeMateOptions<T> (
getDisabled (node: TreeOption) { nodeKey: string | undefined
return !!(node.disabled || node.checkboxDisabled) ): TreeMateOptions<T, T, T> {
return {
getKey (node: T) {
return nodeKey ? (node as any)[nodeKey] : (node as any).key
},
getDisabled (node: T) {
return !!((node as any).disabled || (node as any).checkboxDisabled)
}
} }
} }
@ -94,6 +107,7 @@ const treeProps = {
type: Boolean, type: Boolean,
default: true default: true
}, },
nodeKey: String,
checkable: Boolean, checkable: Boolean,
draggable: Boolean, draggable: Boolean,
blockNode: Boolean, blockNode: Boolean,
@ -215,7 +229,12 @@ export default defineComponent({
// We don't expect data source to change so we just determine it once // We don't expect data source to change so we just determine it once
const displayTreeMateRef = props.internalDisplayTreeMate const displayTreeMateRef = props.internalDisplayTreeMate
? toRef(props, 'internalDisplayTreeMate') ? toRef(props, 'internalDisplayTreeMate')
: computed(() => createTreeMate(props.data, treeMateOptions)) : computed(() =>
createTreeMate<TreeOption>(
props.data,
createTreeMateOptions(props.nodeKey)
)
)
const dataTreeMateRef = props.internalDataTreeMate const dataTreeMateRef = props.internalDataTreeMate
? toRef(props, 'internalDataTreeMate') ? toRef(props, 'internalDataTreeMate')
: displayTreeMateRef : displayTreeMateRef