feat: tree and treeSelect support number key #343

pull/344/head
tangjinzhou 2018-12-26 20:41:01 +08:00
parent 14b8d672c2
commit 793a5ac97e
14 changed files with 118 additions and 104 deletions

View File

@ -12,7 +12,7 @@
| dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width | boolean | true | | dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width | boolean | true |
| dropdownStyle | To set the style of the dropdown menu | object | - | | dropdownStyle | To set the style of the dropdown menu | object | - |
| filterTreeNode | Whether to filter treeNodes by input value. The value of `treeNodeFilterProp` is used for filtering by default. | boolean\|Function(inputValue: string, treeNode: TreeNode) (should return boolean) | Function | | filterTreeNode | Whether to filter treeNodes by input value. The value of `treeNodeFilterProp` is used for filtering by default. | boolean\|Function(inputValue: string, treeNode: TreeNode) (should return boolean) | Function |
| getPopupContainer | To set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | () => document.body | | getPopupContainer | To set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. | Function(triggerNode) | () => document.body |
| labelInValue | whether to embed label in value, turn the format of value from `string` to `{value: string, label: VNode, halfChecked: string[]}` | boolean | false | | labelInValue | whether to embed label in value, turn the format of value from `string` to `{value: string, label: VNode, halfChecked: string[]}` | boolean | false |
| loadData | Load data asynchronously. | function(node) | - | | loadData | Load data asynchronously. | function(node) | - |
| multiple | Support multiple or not, will be `true` when enable `treeCheckable`. | boolean | false | | multiple | Support multiple or not, will be `true` when enable `treeCheckable`. | boolean | false |
@ -27,8 +27,8 @@
| treeData | Data of the treeNodes, manual construction work is no longer needed if this property has been set(ensure the Uniqueness of each value) | array<{ value, label, children, [disabled, disableCheckbox, selectable] }> | \[] | | treeData | Data of the treeNodes, manual construction work is no longer needed if this property has been set(ensure the Uniqueness of each value) | array<{ value, label, children, [disabled, disableCheckbox, selectable] }> | \[] |
| treeDataSimpleMode | Enable simple mode of treeData.(treeData should like this: [{id:1, pId:0, value:'1', label:"test1",...},...], pId is parent node's id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false | | treeDataSimpleMode | Enable simple mode of treeData.(treeData should like this: [{id:1, pId:0, value:'1', label:"test1",...},...], pId is parent node's id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false |
| treeDefaultExpandAll | Whether to expand all treeNodes by default | boolean | false | | treeDefaultExpandAll | Whether to expand all treeNodes by default | boolean | false |
| treeDefaultExpandedKeys | Default expanded treeNodes | string\[] | - | | treeDefaultExpandedKeys | Default expanded treeNodes | string\[] \| number\[] | - |
| treeExpandedKeys | Set expanded keys | string\[] | - | | treeExpandedKeys(.sync) | Set expanded keys | string\[] \| number\[] | - |
| treeNodeFilterProp | Will be used for filtering if `filterTreeNode` returns true | string | 'value' | | treeNodeFilterProp | Will be used for filtering if `filterTreeNode` returns true | string | 'value' |
| treeNodeLabelProp | Will render as content of select | string | 'title' | | treeNodeLabelProp | Will render as content of select | string | 'title' |
| value(v-model) | To set the current selected treeNode(s). | string\|string\[] | - | | value(v-model) | To set the current selected treeNode(s). | string\|string\[] | - |
@ -58,7 +58,7 @@
| disableCheckbox | Disables the checkbox of the treeNode | boolean | false | | disableCheckbox | Disables the checkbox of the treeNode | boolean | false |
| disabled | Disabled or not | boolean | false | | disabled | Disabled or not | boolean | false |
| isLeaf | Leaf node or not | boolean | false | | isLeaf | Leaf node or not | boolean | false |
| key | Required property, should be unique in the tree | string | - | | key | Required property, should be unique in the tree | string \| number | - |
| title | Content showed on the treeNodes | string\|slot | '---' | | title | Content showed on the treeNodes | string\|slot | '---' |
| value | Will be treated as `treeNodeFilterProp` by default, should be unique in the tree | string | - | | value | Will be treated as `treeNodeFilterProp` by default, should be unique in the tree | string | - |
| scopedSlots | When using treeNodes, you can use this property to configure the properties that support the slot, such as `scopedSlots: { title: 'XXX'}` | object | - | | scopedSlots | When using treeNodes, you can use this property to configure the properties that support the slot, such as `scopedSlots: { title: 'XXX'}` | object | - |

View File

@ -27,8 +27,8 @@
| treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点value 在整个树范围内唯一) | array<{value, label, children, [disabled, disableCheckbox, selectable]}> | \[] | | treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点value 在整个树范围内唯一) | array<{value, label, children, [disabled, disableCheckbox, selectable]}> | \[] |
| treeDataSimpleMode | 使用简单格式的 treeData具体设置参考可设置的类型 (此时 treeData 应变为这样的数据结构: [{id:1, pId:0, value:'1', label:"test1",...},...], `pId` 是父节点的 id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false | | treeDataSimpleMode | 使用简单格式的 treeData具体设置参考可设置的类型 (此时 treeData 应变为这样的数据结构: [{id:1, pId:0, value:'1', label:"test1",...},...], `pId` 是父节点的 id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false |
| treeDefaultExpandAll | 默认展开所有树节点 | boolean | false | | treeDefaultExpandAll | 默认展开所有树节点 | boolean | false |
| treeDefaultExpandedKeys | 默认展开的树节点 | string\[] | - | | treeDefaultExpandedKeys | 默认展开的树节点 | string\[] \| number\[] | - |
| treeExpandedKeys | 设置展开的树节点 | string\[] | - | | treeExpandedKeys(.sync) | 设置展开的树节点 | string\[] \| number\[] | - |
| treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | string | 'value' | | treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | string | 'value' |
| treeNodeLabelProp | 作为显示的 prop 设置 | string | 'title' | | treeNodeLabelProp | 作为显示的 prop 设置 | string | 'title' |
| value(v-model) | 指定当前选中的条目 | string/string\[] | - | | value(v-model) | 指定当前选中的条目 | string/string\[] | - |
@ -59,7 +59,7 @@
| disableCheckbox | 禁掉 checkbox | boolean | false | | disableCheckbox | 禁掉 checkbox | boolean | false |
| disabled | 是否禁用 | boolean | false | | disabled | 是否禁用 | boolean | false |
| isLeaf | 是否是叶子节点 | boolean | false | | isLeaf | 是否是叶子节点 | boolean | false |
| key | 此项必须设置(其值在整个树范围内唯一) | string | - | | key | 此项必须设置(其值在整个树范围内唯一) | string \| number | - |
| title | 树节点显示的内容 | string\|slot | '---' | | title | 树节点显示的内容 | string\|slot | '---' |
| value | 默认根据此属性值进行筛选(其值在整个树范围内唯一) | string | - | | value | 默认根据此属性值进行筛选(其值在整个树范围内唯一) | string | - |
| scopedSlots | 使用treeData时可以通过该属性配置支持slot的属性`scopedSlots: { title: 'XXX'}` | object | - | | scopedSlots | 使用treeData时可以通过该属性配置支持slot的属性`scopedSlots: { title: 'XXX'}` | object | - |

View File

@ -20,7 +20,7 @@ export const TreeSelectProps = () => ({
maxTagCount: PropTypes.number, maxTagCount: PropTypes.number,
maxTagPlaceholder: PropTypes.any, maxTagPlaceholder: PropTypes.any,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.array]), value: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.array]),
defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.array]),
multiple: PropTypes.bool, multiple: PropTypes.bool,
// onSelect: (value: any) => void, // onSelect: (value: any) => void,
// onChange: (value: any, label: any) => void, // onChange: (value: any, label: any) => void,
@ -36,8 +36,8 @@ export const TreeSelectProps = () => ({
dropdownClassName: PropTypes.string, dropdownClassName: PropTypes.string,
dropdownMatchSelectWidth: PropTypes.bool, dropdownMatchSelectWidth: PropTypes.bool,
treeDefaultExpandAll: PropTypes.bool, treeDefaultExpandAll: PropTypes.bool,
treeExpandedKeys: PropTypes.arrayOf(String), treeExpandedKeys: PropTypes.array,
treeDefaultExpandedKeys: PropTypes.arrayOf(String), treeDefaultExpandedKeys: PropTypes.array,
treeNodeFilterProp: PropTypes.string, treeNodeFilterProp: PropTypes.string,
treeNodeLabelProp: PropTypes.string, treeNodeLabelProp: PropTypes.string,
}) })

View File

@ -144,6 +144,7 @@ export default {
} }
newState._selectedKeys = newSelectedKeys newState._selectedKeys = newSelectedKeys
this.$emit('update:selectedKeys', newSelectedKeys)
this.$emit('select', newSelectedKeys, event) this.$emit('select', newSelectedKeys, event)
this.setUncontrolledState(newState) this.setUncontrolledState(newState)
@ -188,7 +189,7 @@ export default {
ref: 'tree', ref: 'tree',
class: `${prefixCls}-directory`, class: `${prefixCls}-directory`,
on: { on: {
...this.$listeners, ...omit(this.$listeners, ['update:selectedKeys']),
select: this.onSelect, select: this.onSelect,
click: this.onClick, click: this.onClick,
doubleclick: this.onDoubleClick, doubleclick: this.onDoubleClick,

View File

@ -23,25 +23,25 @@ function TreeProps () {
/** 默认展开对应树节点 */ /** 默认展开对应树节点 */
defaultExpandParent: PropTypes.bool, defaultExpandParent: PropTypes.bool,
/** 默认展开指定的树节点 */ /** 默认展开指定的树节点 */
defaultExpandedKeys: PropTypes.arrayOf(String), defaultExpandedKeys: PropTypes.array,
/** (受控)展开指定的树节点 */ /** (受控)展开指定的树节点 */
expandedKeys: PropTypes.arrayOf(String), expandedKeys: PropTypes.array,
/** (受控)选中复选框的树节点 */ /** (受控)选中复选框的树节点 */
checkedKeys: PropTypes.oneOfType( checkedKeys: PropTypes.oneOfType(
[ [
PropTypes.arrayOf(PropTypes.string), PropTypes.array,
PropTypes.shape({ PropTypes.shape({
checked: PropTypes.arrayOf(String), checked: PropTypes.array,
halfChecked: PropTypes.arrayOf(String), halfChecked: PropTypes.array,
}).loose, }).loose,
] ]
), ),
/** 默认选中复选框的树节点 */ /** 默认选中复选框的树节点 */
defaultCheckedKeys: PropTypes.arrayOf(String), defaultCheckedKeys: PropTypes.array,
/** (受控)设置选中的树节点 */ /** (受控)设置选中的树节点 */
selectedKeys: PropTypes.arrayOf(String), selectedKeys: PropTypes.array,
/** 默认选中的树节点 */ /** 默认选中的树节点 */
defaultSelectedKeys: PropTypes.arrayOf(String), defaultSelectedKeys: PropTypes.array,
selectable: PropTypes.bool, selectable: PropTypes.bool,
/** 展开/收起节点时触发 */ /** 展开/收起节点时触发 */
// onExpand: (expandedKeys: string[], info: AntTreeNodeExpandedEvent) => void | PromiseLike<any>, // onExpand: (expandedKeys: string[], info: AntTreeNodeExpandedEvent) => void | PromiseLike<any>,
@ -57,7 +57,7 @@ function TreeProps () {
filterAntTreeNode: PropTypes.func, filterAntTreeNode: PropTypes.func,
/** 异步加载数据 */ /** 异步加载数据 */
loadData: PropTypes.func, loadData: PropTypes.func,
loadedKeys: PropTypes.arrayOf(String), loadedKeys: PropTypes.array,
// onLoaded: (loadedKeys: string[], info: { event: 'load', node: AntTreeNode; }) => void, // onLoaded: (loadedKeys: string[], info: { event: 'load', node: AntTreeNode; }) => void,
/** 响应右键点击 */ /** 响应右键点击 */
// onRightClick: (options: AntTreeNodeMouseEvent) => void, // onRightClick: (options: AntTreeNodeMouseEvent) => void,
@ -183,9 +183,7 @@ export default {
__propsSymbol__: Symbol(), __propsSymbol__: Symbol(),
switcherIcon: this.renderSwitcherIcon, switcherIcon: this.renderSwitcherIcon,
}, },
on: { on: this.$listeners,
...this.$listeners,
},
ref: 'tree', ref: 'tree',
class: !showIcon && `${prefixCls}-icon-hide`, class: !showIcon && `${prefixCls}-icon-hide`,
} }

View File

@ -8,21 +8,21 @@
| treeData | treeNode of tree, please use `treeNodes` before v1.1.4 | array | - | | treeData | treeNode of tree, please use `treeNodes` before v1.1.4 | array | - |
| autoExpandParent | Whether to automatically expand a parent treeNode | boolean | true | | autoExpandParent | Whether to automatically expand a parent treeNode | boolean | true |
| checkable | Adds a `Checkbox` before the treeNodes | boolean | false | | checkable | Adds a `Checkbox` before the treeNodes | boolean | false |
| checkedKeys(v-model) | (Controlled) Specifies the keys of the checked treeNodes (PS: When this specifies the key of a treeNode which is also a parent treeNode, all the children treeNodes of will be checked; and vice versa, when it specifies the key of a treeNode which is a child treeNode, its parent treeNode will also be checked. When `checkable` and `checkStrictly` is true, its object has `checked` and `halfChecked` property. Regardless of whether the child or parent treeNode is checked, they won't impact each other. | string\[] \| {checked: string\[], halfChecked: string\[]} | \[] | | checkedKeys(v-model) | (Controlled) Specifies the keys of the checked treeNodes (PS: When this specifies the key of a treeNode which is also a parent treeNode, all the children treeNodes of will be checked; and vice versa, when it specifies the key of a treeNode which is a child treeNode, its parent treeNode will also be checked. When `checkable` and `checkStrictly` is true, its object has `checked` and `halfChecked` property. Regardless of whether the child or parent treeNode is checked, they won't impact each other. | string\[] \| number\[] \| {checked: string\[] \| number\[], halfChecked: string\[] \| number\[]} | \[] |
| checkStrictly | Check treeNode precisely; parent treeNode and children treeNodes are not associated | boolean | false | | checkStrictly | Check treeNode precisely; parent treeNode and children treeNodes are not associated | boolean | false |
| defaultCheckedKeys | Specifies the keys of the default checked treeNodes | string\[] | \[] | | defaultCheckedKeys | Specifies the keys of the default checked treeNodes | string\[] \| number\[] | \[] |
| defaultExpandAll | Whether to expand all treeNodes by default | boolean | false | | defaultExpandAll | Whether to expand all treeNodes by default | boolean | false |
| defaultExpandedKeys | Specify the keys of the default expanded treeNodes | string\[] | \[] | | defaultExpandedKeys | Specify the keys of the default expanded treeNodes | string\[] \| number\[] | \[] |
| defaultExpandParent | auto expand parent treeNodes when init | bool | true | | defaultExpandParent | auto expand parent treeNodes when init | bool | true |
| defaultSelectedKeys | Specifies the keys of the default selected treeNodes | string\[] | \[] | | defaultSelectedKeys | Specifies the keys of the default selected treeNodes | string\[] \| number\[] | \[] |
| disabled | whether disabled the tree | bool | false | | disabled | whether disabled the tree | bool | false |
| draggable | Specifies whether this Tree is draggable (IE > 8) | boolean | false | | draggable | Specifies whether this Tree is draggable (IE > 8) | boolean | false |
| expandedKeys(.sync) | (Controlled) Specifies the keys of the expanded treeNodes | string\[] | \[] | | expandedKeys(.sync) | (Controlled) Specifies the keys of the expanded treeNodes | string\[] \| number\[] | \[] |
| filterTreeNode | Defines a function to filter (highlight) treeNodes. When the function returns `true`, the corresponding treeNode will be highlighted | function(node) | - | | filterTreeNode | Defines a function to filter (highlight) treeNodes. When the function returns `true`, the corresponding treeNode will be highlighted | function(node) | - |
| loadData | Load data asynchronously | function(node) | - | | loadData | Load data asynchronously | function(node) | - |
| loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] | \[] | | loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] \| number\[] | \[] |
| multiple | Allows selecting multiple treeNodes | boolean | false | | multiple | Allows selecting multiple treeNodes | boolean | false |
| selectedKeys(.sync) | (Controlled) Specifies the keys of the selected treeNodes | string\[] | - | | selectedKeys(.sync) | (Controlled) Specifies the keys of the selected treeNodes | string\[] \| number\[] | - |
| showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false | | showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false |
| showLine | Shows a connecting line | boolean | false | | showLine | Shows a connecting line | boolean | false |
@ -54,7 +54,7 @@ One of the Tree `treeNode` prop for describing the tree's node, TreeNode has the
| disabled | Disables the treeNode | boolean | false | | disabled | Disables the treeNode | boolean | false |
| icon | customize icon. When you pass component, whose render will receive full TreeNode props as component props | slot\|slot-scope | - | | icon | customize icon. When you pass component, whose render will receive full TreeNode props as component props | slot\|slot-scope | - |
| isLeaf | Determines if this is a leaf node(effective when `loadData` is specified) | boolean | false | | isLeaf | Determines if this is a leaf node(effective when `loadData` is specified) | boolean | false |
| key | Used with (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys. P.S.: It must be unique in all of treeNodes of the tree! | string | internal calculated position of treeNode | | key | Used with (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys. P.S.: It must be unique in all of treeNodes of the tree! | string \| number | internal calculated position of treeNode |
| selectable | Set whether the treeNode can be selected | boolean | true | | selectable | Set whether the treeNode can be selected | boolean | true |
| title | Title | string\|slot\|slot-scope | '---' | | title | Title | string\|slot\|slot-scope | '---' |
| slots | When using treeNodes, you can use this property to configure the properties that support the slot, such as `slots: { title: 'XXX'}` | object | - | | slots | When using treeNodes, you can use this property to configure the properties that support the slot, such as `slots: { title: 'XXX'}` | object | - |

View File

@ -8,21 +8,21 @@
| treeData | 节点的配置描述,具体项见下表, 1.1.4之前的版本使用`treeNodes` | array | -- | | treeData | 节点的配置描述,具体项见下表, 1.1.4之前的版本使用`treeNodes` | array | -- |
| autoExpandParent | 是否自动展开父节点 | boolean | true | | autoExpandParent | 是否自动展开父节点 | boolean | true |
| checkable | 节点前添加 Checkbox 复选框 | boolean | false | | checkable | 节点前添加 Checkbox 复选框 | boolean | false |
| checkedKeys(v-model) | 受控选中复选框的树节点注意父子节点有关联如果传入父节点key则子节点自动选中相应当子节点key都传入父节点也自动选中。当设置`checkable`和`checkStrictly`,它是一个有`checked`和`halfChecked`属性的对象,并且父子节点的选中与否不再关联 | string\[] \| {checked: string\[], halfChecked: string\[]} | \[] | | checkedKeys(v-model) | 受控选中复选框的树节点注意父子节点有关联如果传入父节点key则子节点自动选中相应当子节点key都传入父节点也自动选中。当设置`checkable`和`checkStrictly`,它是一个有`checked`和`halfChecked`属性的对象,并且父子节点的选中与否不再关联 | string\[] \| number\[] \| {checked: string\[] \| number\[], halfChecked: string\[] \| number\[]} | \[] |
| checkStrictly | checkable状态下节点选择完全受控父子节点选中状态不再关联 | boolean | false | | checkStrictly | checkable状态下节点选择完全受控父子节点选中状态不再关联 | boolean | false |
| defaultCheckedKeys | 默认选中复选框的树节点 | string\[] | \[] | | defaultCheckedKeys | 默认选中复选框的树节点 | string\[] \| number\[] | \[] |
| defaultExpandAll | 默认展开所有树节点 | boolean | false | | defaultExpandAll | 默认展开所有树节点 | boolean | false |
| defaultExpandedKeys | 默认展开指定的树节点 | string\[] | \[] | | defaultExpandedKeys | 默认展开指定的树节点 | string\[] \| number\[] | \[] |
| defaultExpandParent | 默认展开父节点 | bool | true | | defaultExpandParent | 默认展开父节点 | bool | true |
| defaultSelectedKeys | 默认选中的树节点 | string\[] | \[] | | defaultSelectedKeys | 默认选中的树节点 | string\[] \| number\[] | \[] |
| disabled | 将树禁用 | bool | false | | disabled | 将树禁用 | bool | false |
| draggable | 设置节点可拖拽 | boolean | false | | draggable | 设置节点可拖拽 | boolean | false |
| expandedKeys(.sync) | (受控)展开指定的树节点 | string\[] | \[] | | expandedKeys(.sync) | (受控)展开指定的树节点 | string\[] \| number\[] | \[] |
| filterTreeNode | 按需筛选树节点高亮返回true | function(node) | - | | filterTreeNode | 按需筛选树节点高亮返回true | function(node) | - |
| loadData | 异步加载数据 | function(node) | - | | loadData | 异步加载数据 | function(node) | - |
| loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] | \[] | | loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] \| number\[] | \[] |
| multiple | 支持点选多个节点(节点本身) | boolean | false | | multiple | 支持点选多个节点(节点本身) | boolean | false |
| selectedKeys(.sync) | (受控)设置选中的树节点 | string\[] | - | | selectedKeys(.sync) | (受控)设置选中的树节点 | string\[] \| number\[] | - |
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true需要自行定义图标相关样式 | boolean | false | | showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true需要自行定义图标相关样式 | boolean | false |
| showLine | 是否展示连接线 | boolean | false | | showLine | 是否展示连接线 | boolean | false |
@ -55,7 +55,7 @@
| disabled | 禁掉响应 | boolean | false | | disabled | 禁掉响应 | boolean | false |
| icon | 自定义图标。可接收组件props 为当前节点 props | slot\|slot-scope | - | | icon | 自定义图标。可接收组件props 为当前节点 props | slot\|slot-scope | - |
| isLeaf | 设置为叶子节点(设置了`loadData`时有效) | boolean | false | | isLeaf | 设置为叶子节点(设置了`loadData`时有效) | boolean | false |
| key | 被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复! | string | 内部计算出的节点位置 | | key | 被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复! | string \| number | 内部计算出的节点位置 |
| selectable | 设置节点是否可被选中 | boolean | true | | selectable | 设置节点是否可被选中 | boolean | true |
| title | 标题 | string\|slot\|slot-scope | '---' | | title | 标题 | string\|slot\|slot-scope | '---' |
| slots | 使用treeNodes时可以通过该属性配置支持slot的属性`slots: { title: 'XXX'}` | object | - | | slots | 使用treeNodes时可以通过该属性配置支持slot的属性`slots: { title: 'XXX'}` | object | - |

View File

@ -24,7 +24,7 @@ function traverseNodesKey (rootChildren, callback) {
export function getFullKeyList (children) { export function getFullKeyList (children) {
const { keyEntities } = convertTreeToEntities(children) const { keyEntities } = convertTreeToEntities(children)
return Object.keys(keyEntities) return [...keyEntities.keys()]
} }
/** 计算选中范围只考虑expanded情况以优化性能 */ /** 计算选中范围只考虑expanded情况以优化性能 */

View File

@ -38,7 +38,7 @@ function getDerivedStateFromProps (nextProps, prevState) {
filteredTreeNodes.length && filteredTreeNodes.length &&
filteredTreeNodes !== prevProps.filteredTreeNodes filteredTreeNodes !== prevProps.filteredTreeNodes
) { ) {
newState._expandedKeyList = Object.keys(keyEntities) newState._expandedKeyList = [...keyEntities.keys()]
} }
// Cache `expandedKeyList` when filter set // Cache `expandedKeyList` when filter set
@ -56,7 +56,7 @@ function getDerivedStateFromProps (nextProps, prevState) {
// Clean loadedKeys if key not exist in keyEntities anymore // Clean loadedKeys if key not exist in keyEntities anymore
if (nextProps.loadData) { if (nextProps.loadData) {
newState._loadedKeys = loadedKeys.filter(key => key in keyEntities) newState._loadedKeys = loadedKeys.filter(key => keyEntities.has(key))
} }
return newState return newState
@ -70,7 +70,7 @@ const BasePopup = {
valueList: PropTypes.array, valueList: PropTypes.array,
searchHalfCheckedKeys: PropTypes.array, searchHalfCheckedKeys: PropTypes.array,
valueEntities: PropTypes.object, valueEntities: PropTypes.object,
keyEntities: PropTypes.object, keyEntities: Map,
treeIcon: PropTypes.bool, treeIcon: PropTypes.bool,
treeLine: PropTypes.bool, treeLine: PropTypes.bool,
treeNodeFilterProp: PropTypes.string, treeNodeFilterProp: PropTypes.string,
@ -114,7 +114,7 @@ const BasePopup = {
// TODO: make `expandedKeyList` control // TODO: make `expandedKeyList` control
let expandedKeyList = treeDefaultExpandedKeys let expandedKeyList = treeDefaultExpandedKeys
if (treeDefaultExpandAll) { if (treeDefaultExpandAll) {
expandedKeyList = Object.keys(keyEntities) expandedKeyList = [...keyEntities.keys()]
} }
const state = { const state = {
@ -140,6 +140,7 @@ const BasePopup = {
this.__emit('treeExpanded') this.__emit('treeExpanded')
}) })
} }
this.__emit('update:treeExpandedKeys', expandedKeyList)
this.__emit('treeExpand', expandedKeyList) this.__emit('treeExpand', expandedKeyList)
}, },

View File

@ -44,7 +44,7 @@ import {
cleanEntity, cleanEntity,
} from './util' } from './util'
import SelectNode from './SelectNode' import SelectNode from './SelectNode'
import { initDefaultProps, getOptionProps, mergeProps, getPropsData } from '../../_util/props-util' import { initDefaultProps, getOptionProps, mergeProps, getPropsData, filterEmpty } from '../../_util/props-util'
function getWatch (keys = []) { function getWatch (keys = []) {
const watch = {} const watch = {}
keys.forEach(k => { keys.forEach(k => {
@ -162,7 +162,8 @@ const Select = {
_missValueList: [], // Contains the value not in the tree _missValueList: [], // Contains the value not in the tree
_selectorValueList: [], // Used for multiple selector _selectorValueList: [], // Used for multiple selector
_valueEntities: {}, _valueEntities: {},
_keyEntities: {}, _posEntities: new Map(),
_keyEntities: new Map(),
_searchValue: '', _searchValue: '',
_prevProps: {}, _prevProps: {},
_init: true, _init: true,
@ -286,7 +287,7 @@ const Select = {
// processState('children', (propValue) => { // processState('children', (propValue) => {
// treeNodes = Array.isArray(propValue) ? propValue : [propValue] // treeNodes = Array.isArray(propValue) ? propValue : [propValue]
// }) // })
treeNodes = this.$slots.default treeNodes = filterEmpty(this.$slots.default)
} }
// Convert `treeData` to entities // Convert `treeData` to entities
@ -354,7 +355,7 @@ const Select = {
// Format value list again for internal usage // Format value list again for internal usage
newState._valueList = checkedKeys.map(key => ({ newState._valueList = checkedKeys.map(key => ({
value: (newState._keyEntities || prevState._keyEntities)[key].value, value: (newState._keyEntities || prevState._keyEntities).get(key).value,
})) }))
} else { } else {
newState._valueList = filteredValueList newState._valueList = filteredValueList
@ -621,7 +622,7 @@ const Select = {
).checkedKeys ).checkedKeys
} }
newValueList = keyList.map(key => { newValueList = keyList.map(key => {
const props = getPropsData(keyEntities[key].node) const props = getPropsData(keyEntities.get(key).node)
return { return {
value: props.value, value: props.value,
label: props[treeNodeLabelProp], label: props[treeNodeLabelProp],
@ -731,10 +732,10 @@ const Select = {
).checkedKeys ).checkedKeys
} }
checkedNodeList = keyList.map(key => keyEntities[key].node) checkedNodeList = keyList.map(key => keyEntities.get(key).node)
// Let's follow as not `treeCheckStrictly` format // Let's follow as not `treeCheckStrictly` format
extraInfo.allCheckedNodes = keyList.map(key => cleanEntity(keyEntities[key])) extraInfo.allCheckedNodes = keyList.map(key => cleanEntity(keyEntities.get(key)))
} else if (treeCheckStrictly) { } else if (treeCheckStrictly) {
extraInfo.allCheckedNodes = nodeEventInfo.checkedNodes extraInfo.allCheckedNodes = nodeEventInfo.checkedNodes
} else { } else {

View File

@ -336,13 +336,17 @@ export function formatSelectorValue (valueList, props, valueEntities) {
* This will change the label to title value * This will change the label to title value
*/ */
function processProps (props) { function processProps (props) {
const { title, label, key, value, class: cls, style, on = {}} = props const { title, label, value, class: cls, style, on = {}} = props
let key = props.key
if (!key && (key === undefined || key === null)) {
key = value
}
const p = { const p = {
props: omit(props, ['on', 'key', 'class', 'className', 'style']), props: omit(props, ['on', 'key', 'class', 'className', 'style']),
on, on,
class: cls || props.className, class: cls || props.className,
style: style, style: style,
key: typeof key === 'number' ? String(key) : (key || value), key,
} }
// Warning user not to use deprecated label prop. // Warning user not to use deprecated label prop.
if (label && !title) { if (label && !title) {

View File

@ -52,22 +52,22 @@ const Tree = {
defaultExpandParent: PropTypes.bool, defaultExpandParent: PropTypes.bool,
autoExpandParent: PropTypes.bool, autoExpandParent: PropTypes.bool,
defaultExpandAll: PropTypes.bool, defaultExpandAll: PropTypes.bool,
defaultExpandedKeys: PropTypes.arrayOf(PropTypes.string), defaultExpandedKeys: PropTypes.array,
expandedKeys: PropTypes.arrayOf(PropTypes.string), expandedKeys: PropTypes.array,
defaultCheckedKeys: PropTypes.arrayOf(PropTypes.string), defaultCheckedKeys: PropTypes.array,
checkedKeys: PropTypes.oneOfType([ checkedKeys: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), PropTypes.array,
PropTypes.object, PropTypes.object,
]), ]),
defaultSelectedKeys: PropTypes.arrayOf(PropTypes.string), defaultSelectedKeys: PropTypes.array,
selectedKeys: PropTypes.arrayOf(PropTypes.string), selectedKeys: PropTypes.array,
// onClick: PropTypes.func, // onClick: PropTypes.func,
// onDoubleClick: PropTypes.func, // onDoubleClick: PropTypes.func,
// onExpand: PropTypes.func, // onExpand: PropTypes.func,
// onCheck: PropTypes.func, // onCheck: PropTypes.func,
// onSelect: PropTypes.func, // onSelect: PropTypes.func,
loadData: PropTypes.func, loadData: PropTypes.func,
loadedKeys: PropTypes.arrayOf(PropTypes.string), loadedKeys: PropTypes.array,
// onMouseEnter: PropTypes.func, // onMouseEnter: PropTypes.func,
// onMouseLeave: PropTypes.func, // onMouseLeave: PropTypes.func,
// onRightClick: PropTypes.func, // onRightClick: PropTypes.func,
@ -105,8 +105,8 @@ const Tree = {
warning(this.$props.children, 'please children prop replace slots.default') warning(this.$props.children, 'please children prop replace slots.default')
this.needSyncKeys = {} this.needSyncKeys = {}
const state = { const state = {
_posEntities: {}, _posEntities: new Map(),
_keyEntities: {}, _keyEntities: new Map(),
_expandedKeys: [], _expandedKeys: [],
_selectedKeys: [], _selectedKeys: [],
_checkedKeys: [], _checkedKeys: [],
@ -177,7 +177,7 @@ const Tree = {
newState._expandedKeys = (props.autoExpandParent || (!_prevProps && props.defaultExpandParent)) newState._expandedKeys = (props.autoExpandParent || (!_prevProps && props.defaultExpandParent))
? conductExpandParent(props.expandedKeys, keyEntities) : props.expandedKeys ? conductExpandParent(props.expandedKeys, keyEntities) : props.expandedKeys
} else if (!_prevProps && props.defaultExpandAll) { } else if (!_prevProps && props.defaultExpandAll) {
newState._expandedKeys = Object.keys(keyEntities) newState._expandedKeys = [...keyEntities.keys()]
} else if (!_prevProps && props.defaultExpandedKeys) { } else if (!_prevProps && props.defaultExpandedKeys) {
newState._expandedKeys = (props.autoExpandParent || props.defaultExpandParent) newState._expandedKeys = (props.autoExpandParent || props.defaultExpandParent)
? conductExpandParent(props.defaultExpandedKeys, keyEntities) : props.defaultExpandedKeys ? conductExpandParent(props.defaultExpandedKeys, keyEntities) : props.defaultExpandedKeys
@ -380,7 +380,7 @@ const Tree = {
// [Legacy] Not found related usage in doc or upper libs // [Legacy] Not found related usage in doc or upper libs
const selectedNodes = selectedKeys.map(key => { const selectedNodes = selectedKeys.map(key => {
const entity = keyEntities[key] const entity = keyEntities.get(key)
if (!entity) return null if (!entity) return null
return entity.node return entity.node
@ -395,6 +395,7 @@ const Tree = {
selectedNodes, selectedNodes,
nativeEvent: e, nativeEvent: e,
} }
this.__emit('update:selectedKeys', selectedKeys)
this.__emit('select', selectedKeys, eventObj) this.__emit('select', selectedKeys, eventObj)
}, },
onNodeCheck (e, treeNode, checked) { onNodeCheck (e, treeNode, checked) {
@ -417,7 +418,7 @@ const Tree = {
checkedObj = { checked: checkedKeys, halfChecked: halfCheckedKeys } checkedObj = { checked: checkedKeys, halfChecked: halfCheckedKeys }
eventObj.checkedNodes = checkedKeys eventObj.checkedNodes = checkedKeys
.map(key => keyEntities[key]) .map(key => keyEntities.get(key))
.filter(entity => entity) .filter(entity => entity)
.map(entity => entity.node) .map(entity => entity.node)
@ -435,7 +436,7 @@ const Tree = {
eventObj.halfCheckedKeys = halfCheckedKeys eventObj.halfCheckedKeys = halfCheckedKeys
checkedKeys.forEach((key) => { checkedKeys.forEach((key) => {
const entity = keyEntities[key] const entity = keyEntities.get(key)
if (!entity) return if (!entity) return
const { node, pos } = entity const { node, pos } = entity
@ -516,6 +517,7 @@ const Tree = {
expanded: targetExpanded, expanded: targetExpanded,
nativeEvent: e, nativeEvent: e,
}) })
this.__emit('update:expandedKeys', expandedKeys)
// Async Load data // Async Load data
if (targetExpanded && loadData) { if (targetExpanded && loadData) {
@ -581,8 +583,11 @@ const Tree = {
_dropPosition: dropPosition, _dropPosition: dropPosition,
} = this.$data } = this.$data
const pos = getPosition(level, index) const pos = getPosition(level, index)
const key = child.key || pos let key = child.key
if (!keyEntities[key]) { if (!key && (key === undefined || key === null)) {
key = pos
}
if (!keyEntities.get(key)) {
warnOnlyTreeNode() warnOnlyTreeNode()
return null return null
} }

View File

@ -19,7 +19,7 @@ const TreeNode = {
mixins: [BaseMixin], mixins: [BaseMixin],
__ANT_TREE_NODE: true, __ANT_TREE_NODE: true,
props: initDefaultProps({ props: initDefaultProps({
eventKey: PropTypes.string, // Pass by parent `cloneElement` eventKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // Pass by parent `cloneElement`
prefixCls: PropTypes.string, prefixCls: PropTypes.string,
// className: PropTypes.string, // className: PropTypes.string,
root: PropTypes.object, root: PropTypes.object,

View File

@ -63,11 +63,15 @@ export function traverseTreeNodes (treeNodes, callback) {
// Process node if is not root // Process node if is not root
if (node) { if (node) {
let key = node.key
if (!key && (key === undefined || key === null)) {
key = pos
}
const data = { const data = {
node, node,
index, index,
pos, pos,
key: node.key || pos, key,
parentPos: parent.node ? parent.pos : null, parentPos: parent.node ? parent.pos : null,
} }
callback(data) callback(data)
@ -178,8 +182,8 @@ export function convertDataToTree (h, treeData, processer) {
* @param processTreeEntity User can customize the entity * @param processTreeEntity User can customize the entity
*/ */
export function convertTreeToEntities (treeNodes, { initWrapper, processEntity, onProcessFinished } = {}) { export function convertTreeToEntities (treeNodes, { initWrapper, processEntity, onProcessFinished } = {}) {
const posEntities = {} const posEntities = new Map()
const keyEntities = {} const keyEntities = new Map()
let wrapper = { let wrapper = {
posEntities, posEntities,
keyEntities, keyEntities,
@ -193,11 +197,11 @@ export function convertTreeToEntities (treeNodes, { initWrapper, processEntity,
const { node, index, pos, key, parentPos } = item const { node, index, pos, key, parentPos } = item
const entity = { node, index, key, pos } const entity = { node, index, key, pos }
posEntities[pos] = entity posEntities.set(pos, entity)
keyEntities[key] = entity keyEntities.set(key, entity)
// Fill children // Fill children
entity.parent = posEntities[parentPos] entity.parent = posEntities.get(parentPos)
if (entity.parent) { if (entity.parent) {
entity.parent.children = entity.parent.children || [] entity.parent.children = entity.parent.children || []
entity.parent.children.push(entity) entity.parent.children.push(entity)
@ -241,8 +245,8 @@ export function parseCheckedKeys (keys) {
return null return null
} }
keyProps.checkedKeys = keyListToString(keyProps.checkedKeys) // keyProps.checkedKeys = keyListToString(keyProps.checkedKeys)
keyProps.halfCheckedKeys = keyListToString(keyProps.halfCheckedKeys) // keyProps.halfCheckedKeys = keyListToString(keyProps.halfCheckedKeys)
return keyProps return keyProps
} }
@ -257,22 +261,22 @@ export function parseCheckedKeys (keys) {
* @returns {{checkedKeys: [], halfCheckedKeys: []}} * @returns {{checkedKeys: [], halfCheckedKeys: []}}
*/ */
export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) { export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
const checkedKeys = {} const checkedKeys = new Map()
const halfCheckedKeys = {}; // Record the key has some child checked (include child half checked) const halfCheckedKeys = new Map(); // Record the key has some child checked (include child half checked)
(checkStatus.checkedKeys || []).forEach((key) => { (checkStatus.checkedKeys || []).forEach((key) => {
checkedKeys[key] = true checkedKeys.set(key, true)
}); });
(checkStatus.halfCheckedKeys || []).forEach((key) => { (checkStatus.halfCheckedKeys || []).forEach((key) => {
halfCheckedKeys[key] = true halfCheckedKeys.set(key, true)
}) })
// Conduct up // Conduct up
function conductUp (key) { function conductUp (key) {
if (checkedKeys[key] === isCheck) return if (checkedKeys.get(key) === isCheck) return
const entity = keyEntities[key] const entity = keyEntities.get(key)
if (!entity) return if (!entity) return
const { children, parent, node } = entity const { children, parent, node } = entity
@ -286,8 +290,8 @@ export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
(children || []) (children || [])
.filter(child => !isCheckDisabled(child.node)) .filter(child => !isCheckDisabled(child.node))
.forEach(({ key: childKey }) => { .forEach(({ key: childKey }) => {
const childChecked = checkedKeys[childKey] const childChecked = checkedKeys.get(childKey)
const childHalfChecked = halfCheckedKeys[childKey] const childHalfChecked = halfCheckedKeys.get(childKey)
if (childChecked || childHalfChecked) someChildChecked = true if (childChecked || childHalfChecked) someChildChecked = true
if (!childChecked) everyChildChecked = false if (!childChecked) everyChildChecked = false
@ -295,11 +299,11 @@ export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
// Update checked status // Update checked status
if (isCheck) { if (isCheck) {
checkedKeys[key] = everyChildChecked checkedKeys.set(key, everyChildChecked)
} else { } else {
checkedKeys[key] = false checkedKeys.set(key, false)
} }
halfCheckedKeys[key] = someChildChecked halfCheckedKeys.set(key, someChildChecked)
if (parent) { if (parent) {
conductUp(parent.key) conductUp(parent.key)
@ -308,16 +312,16 @@ export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
// Conduct down // Conduct down
function conductDown (key) { function conductDown (key) {
if (checkedKeys[key] === isCheck) return if (checkedKeys.get(key) === isCheck) return
const entity = keyEntities[key] const entity = keyEntities.get(key)
if (!entity) return if (!entity) return
const { children, node } = entity const { children, node } = entity
if (isCheckDisabled(node)) return if (isCheckDisabled(node)) return
checkedKeys[key] = isCheck; checkedKeys.set(key, isCheck);
(children || []).forEach((child) => { (children || []).forEach((child) => {
conductDown(child.key) conductDown(child.key)
@ -325,14 +329,14 @@ export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
} }
function conduct (key) { function conduct (key) {
const entity = keyEntities[key] const entity = keyEntities.get(key)
if (!entity) { if (!entity) {
warning(false, `'${key}' does not exist in the tree.`) warning(false, `'${key}' does not exist in the tree.`)
return return
} }
const { children, parent, node } = entity const { children, parent, node } = entity
checkedKeys[key] = isCheck checkedKeys.set(key, isCheck)
if (isCheckDisabled(node)) return; if (isCheckDisabled(node)) return;
@ -357,18 +361,18 @@ export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
const halfCheckedKeyList = [] const halfCheckedKeyList = []
// Fill checked list // Fill checked list
Object.keys(checkedKeys).forEach((key) => { for (const [key, value] of checkedKeys) {
if (checkedKeys[key]) { if (value) {
checkedKeyList.push(key) checkedKeyList.push(key)
} }
}) }
// Fill half checked list // Fill half checked list
Object.keys(halfCheckedKeys).forEach((key) => { for (const [key, value] of halfCheckedKeys) {
if (!checkedKeys[key] && halfCheckedKeys[key]) { if (!checkedKeys.get(key) && value) {
halfCheckedKeyList.push(key) halfCheckedKeyList.push(key)
} }
}) }
return { return {
checkedKeys: checkedKeyList, checkedKeys: checkedKeyList,
@ -382,15 +386,15 @@ export function conductCheck (keyList, isCheck, keyEntities, checkStatus = {}) {
* @param keyEntities * @param keyEntities
*/ */
export function conductExpandParent (keyList, keyEntities) { export function conductExpandParent (keyList, keyEntities) {
const expandedKeys = {} const expandedKeys = new Map()
function conductUp (key) { function conductUp (key) {
if (expandedKeys[key]) return if (expandedKeys.get(key)) return
const entity = keyEntities[key] const entity = keyEntities.get(key)
if (!entity) return if (!entity) return
expandedKeys[key] = true expandedKeys.set(key, true)
const { parent, node } = entity const { parent, node } = entity
@ -405,7 +409,7 @@ export function conductExpandParent (keyList, keyEntities) {
conductUp(key) conductUp(key)
}) })
return Object.keys(expandedKeys) return [...expandedKeys.keys()]
} }
/** /**