mirror of
https://github.com/element-plus/element-plus.git
synced 2025-04-06 16:30:35 +08:00
feat(components): [tree/tree-select] add check-on-click-leaf
attribute (#19494)
* chore: last leaf node clickable on `show-checkbox` * chore: revert * chore: leaf node checkable * test: checkable by click on leaf node * chore: test & doc * chore: add version * feat: handle tree-v2 * test: tree-v2
This commit is contained in:
parent
3ef10ec5b8
commit
0ed86e74ce
@ -82,23 +82,24 @@ tree-v2/filter
|
||||
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------- |
|
||||
| data | tree data | array | — |
|
||||
| empty-text | text displayed when data is void | string | — |
|
||||
| props | configuration options, see the following table | object | — |
|
||||
| highlight-current | whether current node is highlighted | boolean | false |
|
||||
| expand-on-click-node | whether to expand or collapse node when clicking on the node, if false, then expand or collapse node only when clicking on the arrow icon. | boolean | true |
|
||||
| check-on-click-node | whether to check or uncheck node when clicking on the node, if false, the node can only be checked or unchecked by clicking on the checkbox. | boolean | false |
|
||||
| default-expanded-keys | array of keys of initially expanded nodes | array | — |
|
||||
| show-checkbox | whether node is selectable | boolean | false |
|
||||
| check-strictly | whether checked state of a node not affects its father and child nodes when `show-checkbox` is `true` | boolean | false |
|
||||
| default-checked-keys | array of keys of initially checked nodes | array | — |
|
||||
| current-node-key | key of initially selected node | string / number | — |
|
||||
| filter-method | this function will be executed on each node when use filter method. if return `false`, tree node will be hidden. | Function(value, data, node) | — |
|
||||
| indent | horizontal indentation of nodes in adjacent levels in pixels | number | 16 |
|
||||
| icon | custom tree node icon | `string \| Component` | — |
|
||||
| item-size ^(2.2.33) | custom tree node height | number | 26 |
|
||||
| Name | Description | Type | Default |
|
||||
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------- |
|
||||
| data | tree data | array | — |
|
||||
| empty-text | text displayed when data is void | string | — |
|
||||
| props | configuration options, see the following table | object | — |
|
||||
| highlight-current | whether current node is highlighted | boolean | false |
|
||||
| expand-on-click-node | whether to expand or collapse node when clicking on the node, if false, then expand or collapse node only when clicking on the arrow icon. | boolean | true |
|
||||
| check-on-click-node | whether to check or uncheck node when clicking on the node, if false, the node can only be checked or unchecked by clicking on the checkbox. | boolean | false |
|
||||
| check-on-click-leaf ^(2.9.6) | whether to check or uncheck node when clicking on leaf node (last children). | ^[boolean] | true |
|
||||
| default-expanded-keys | array of keys of initially expanded nodes | array | — |
|
||||
| show-checkbox | whether node is selectable | boolean | false |
|
||||
| check-strictly | whether checked state of a node not affects its father and child nodes when `show-checkbox` is `true` | boolean | false |
|
||||
| default-checked-keys | array of keys of initially checked nodes | array | — |
|
||||
| current-node-key | key of initially selected node | string / number | — |
|
||||
| filter-method | this function will be executed on each node when use filter method. if return `false`, tree node will be hidden. | Function(value, data, node) | — |
|
||||
| indent | horizontal indentation of nodes in adjacent levels in pixels | number | 16 |
|
||||
| icon | custom tree node icon | `string \| Component` | — |
|
||||
| item-size ^(2.2.33) | custom tree node height | number | 26 |
|
||||
|
||||
### props
|
||||
|
||||
|
@ -125,33 +125,34 @@ tree/draggable
|
||||
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------- |
|
||||
| data | tree data | ^[object]`Array<{[key: string]: any}>` | — |
|
||||
| empty-text | text displayed when data is void | ^[string] | — |
|
||||
| node-key | unique identity key name for nodes, its value should be unique across the whole tree | ^[string] | — |
|
||||
| props | configuration options, see the following table | [props](#props) | — |
|
||||
| render-after-expand | whether to render child nodes only after a parent node is expanded for the first time | ^[boolean] | true |
|
||||
| load | method for loading subtree data, only works when `lazy` is true | ^[Function]`(node, resolve, reject) => void` | — |
|
||||
| render-content | render function for tree node | ^[Function]`(h, { node, data, store }) => void` | — |
|
||||
| highlight-current | whether current node is highlighted | ^[boolean] | false |
|
||||
| default-expand-all | whether to expand all nodes by default | ^[boolean] | false |
|
||||
| expand-on-click-node | whether to expand or collapse node when clicking on the node, if false, then expand or collapse node only when clicking on the arrow icon. | ^[boolean] | true |
|
||||
| check-on-click-node | whether to check or uncheck node when clicking on the node, if false, the node can only be checked or unchecked by clicking on the checkbox. | ^[boolean] | false |
|
||||
| auto-expand-parent | whether to expand father node when a child node is expanded | ^[boolean] | true |
|
||||
| default-expanded-keys | array of keys of initially expanded nodes | ^[object]`Array<string \| number>` | — |
|
||||
| show-checkbox | whether node is selectable | ^[boolean] | false |
|
||||
| check-strictly | whether checked state of a node not affects its father and child nodes when `show-checkbox` is `true` | ^[boolean] | false |
|
||||
| default-checked-keys | array of keys of initially checked nodes | ^[object]`Array<string \| number>` | — |
|
||||
| current-node-key | key of initially selected node | ^[string] / ^[number] | — |
|
||||
| filter-node-method | this function will be executed on each node when use filter method. if return `false`, tree node will be hidden. | ^[Function]`(value, data, node) => boolean` | — |
|
||||
| accordion | whether only one node among the same level can be expanded at one time | ^[boolean] | false |
|
||||
| indent | horizontal indentation of nodes in adjacent levels in pixels | ^[number] | 18 |
|
||||
| icon | custom tree node icon component | ^[string] / ^[Component] | — |
|
||||
| lazy | whether to lazy load leaf node, used with `load` attribute | ^[boolean] | false |
|
||||
| draggable | whether enable tree nodes drag and drop | ^[boolean] | false |
|
||||
| allow-drag | this function will be executed before dragging a node. If `false` is returned, the node can not be dragged | ^[Function]`(node) => boolean` | — |
|
||||
| allow-drop | this function will be executed before the dragging node is dropped. If `false` is returned, the dragging node can not be dropped at the target node. `type` has three possible values: 'prev' (inserting the dragging node before the target node), 'inner' (inserting the dragging node to the target node) and 'next' (inserting the dragging node after the target node) | ^[Function]`(draggingNode, dropNode, type) => boolean` | — |
|
||||
| Name | Description | Type | Default |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------- |
|
||||
| data | tree data | ^[object]`Array<{[key: string]: any}>` | — |
|
||||
| empty-text | text displayed when data is void | ^[string] | — |
|
||||
| node-key | unique identity key name for nodes, its value should be unique across the whole tree | ^[string] | — |
|
||||
| props | configuration options, see the following table | [props](#props) | — |
|
||||
| render-after-expand | whether to render child nodes only after a parent node is expanded for the first time | ^[boolean] | true |
|
||||
| load | method for loading subtree data, only works when `lazy` is true | ^[Function]`(node, resolve, reject) => void` | — |
|
||||
| render-content | render function for tree node | ^[Function]`(h, { node, data, store }) => void` | — |
|
||||
| highlight-current | whether current node is highlighted | ^[boolean] | false |
|
||||
| default-expand-all | whether to expand all nodes by default | ^[boolean] | false |
|
||||
| expand-on-click-node | whether to expand or collapse node when clicking on the node, if false, then expand or collapse node only when clicking on the arrow icon. | ^[boolean] | true |
|
||||
| check-on-click-node | whether to check or uncheck node when clicking on the node, if false, the node can only be checked or unchecked by clicking on the checkbox. | ^[boolean] | false |
|
||||
| check-on-click-leaf ^(2.9.6) | whether to check or uncheck node when clicking on leaf node (last children). | ^[boolean] | true |
|
||||
| auto-expand-parent | whether to expand father node when a child node is expanded | ^[boolean] | true |
|
||||
| default-expanded-keys | array of keys of initially expanded nodes | ^[object]`Array<string \| number>` | — |
|
||||
| show-checkbox | whether node is selectable | ^[boolean] | false |
|
||||
| check-strictly | whether checked state of a node not affects its father and child nodes when `show-checkbox` is `true` | ^[boolean] | false |
|
||||
| default-checked-keys | array of keys of initially checked nodes | ^[object]`Array<string \| number>` | — |
|
||||
| current-node-key | key of initially selected node | ^[string] / ^[number] | — |
|
||||
| filter-node-method | this function will be executed on each node when use filter method. if return `false`, tree node will be hidden. | ^[Function]`(value, data, node) => boolean` | — |
|
||||
| accordion | whether only one node among the same level can be expanded at one time | ^[boolean] | false |
|
||||
| indent | horizontal indentation of nodes in adjacent levels in pixels | ^[number] | 18 |
|
||||
| icon | custom tree node icon component | ^[string] / ^[Component] | — |
|
||||
| lazy | whether to lazy load leaf node, used with `load` attribute | ^[boolean] | false |
|
||||
| draggable | whether enable tree nodes drag and drop | ^[boolean] | false |
|
||||
| allow-drag | this function will be executed before dragging a node. If `false` is returned, the node can not be dragged | ^[Function]`(node) => boolean` | — |
|
||||
| allow-drop | this function will be executed before the dragging node is dropped. If `false` is returned, the dragging node can not be dropped at the target node. `type` has three possible values: 'prev' (inserting the dragging node before the target node), 'inner' (inserting the dragging node to the target node) and 'next' (inserting the dragging node after the target node) | ^[Function]`(draggingNode, dropNode, type) => boolean` | — |
|
||||
|
||||
### props
|
||||
|
||||
|
@ -802,6 +802,45 @@ describe('TreeSelect.vue', () => {
|
||||
expect(select.vm.modelValue).toEqual([5, 6, 4, 2])
|
||||
})
|
||||
|
||||
test('check by click on leaf node', async () => {
|
||||
const { tree, select } = createComponent({
|
||||
props: {
|
||||
showCheckbox: true,
|
||||
},
|
||||
})
|
||||
|
||||
const treeVm = tree.vm
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
|
||||
await tree.findAll('.el-tree-node__content')[0].trigger('click')
|
||||
await tree.findAll('.el-tree-node__content')[1].trigger('click')
|
||||
await tree.findAll('.el-tree-node__content')[2].trigger('click')
|
||||
|
||||
expect(select.vm.modelValue).toEqual(111)
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(3)
|
||||
expect(treeVm.getCheckedNodes(true).length).toEqual(1)
|
||||
})
|
||||
|
||||
test('show-checkbox :check-on-click-leaf="false"', async () => {
|
||||
const { tree, select } = createComponent({
|
||||
props: {
|
||||
showCheckbox: true,
|
||||
checkOnClickLeaf: false,
|
||||
},
|
||||
})
|
||||
|
||||
const treeVm = tree.vm
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
|
||||
await tree.findAll('.el-tree-node__content')[0].trigger('click')
|
||||
await tree.findAll('.el-tree-node__content')[1].trigger('click')
|
||||
await tree.findAll('.el-tree-node__content')[2].trigger('click')
|
||||
|
||||
expect(select.vm.modelValue).toBeUndefined()
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
expect(treeVm.getCheckedNodes(true).length).toEqual(0)
|
||||
})
|
||||
|
||||
test('no checkbox and check on click node', async () => {
|
||||
const { select, tree } = createComponent({
|
||||
props: {
|
||||
|
@ -68,6 +68,7 @@ interface TreeProps {
|
||||
iconClass?: string
|
||||
expandOnClickNode?: boolean
|
||||
checkOnClickNode?: boolean
|
||||
checkOnClickLeaf?: boolean
|
||||
currentNodeKey?: TreeKey
|
||||
filterMethod?: FilterMethod
|
||||
}
|
||||
@ -130,6 +131,7 @@ const createTree = (
|
||||
:icon-class="iconClass"
|
||||
:expand-on-click-node="expandOnClickNode"
|
||||
:check-on-click-node="checkOnClickNode"
|
||||
:check-on-click-leaf="checkOnClickLeaf"
|
||||
:current-node-key="currentNodeKey"
|
||||
:filter-method="filterMethod"
|
||||
@node-click="onNodeClick"
|
||||
@ -162,6 +164,7 @@ const createTree = (
|
||||
iconClass: undefined,
|
||||
expandOnClickNode: true,
|
||||
checkOnClickNode: false,
|
||||
checkOnClickLeaf: true,
|
||||
currentNodeKey: undefined,
|
||||
filterMethod: undefined,
|
||||
...(options.data && options.data()),
|
||||
@ -455,6 +458,137 @@ describe('Virtual Tree', () => {
|
||||
expect(wrapper.findAll('.el-checkbox .is-indeterminate').length).toBe(0)
|
||||
})
|
||||
|
||||
test('showCheckbox checkOnClickLeaf', async () => {
|
||||
const { wrapper, treeRef } = createTree({
|
||||
data() {
|
||||
return {
|
||||
showCheckbox: true,
|
||||
checkOnClickLeaf: true,
|
||||
height: 400,
|
||||
data: [
|
||||
{
|
||||
id: '1',
|
||||
label: 'node-1',
|
||||
children: [
|
||||
{
|
||||
id: '1-1',
|
||||
label: 'node-1-1',
|
||||
children: [
|
||||
{
|
||||
id: '1-1-1',
|
||||
label: 'node-1-1-1',
|
||||
},
|
||||
{
|
||||
id: '1-1-2',
|
||||
label: 'node-1-1-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1-2',
|
||||
label: 'node-1-2',
|
||||
children: [
|
||||
{
|
||||
id: '1-2-1',
|
||||
label: 'node-1-2-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1-3',
|
||||
label: 'node-1-3',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: 'node-2',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
})
|
||||
await nextTick()
|
||||
expect(treeRef.getCheckedKeys()).toHaveLength(0)
|
||||
let nodes = wrapper.findAll(TREE_NODE_CLASS_NAME)
|
||||
await nodes[0].trigger('click')
|
||||
nodes = wrapper.findAll(TREE_NODE_CLASS_NAME)
|
||||
await nodes[1].trigger('click')
|
||||
nodes = wrapper.findAll(TREE_NODE_CLASS_NAME)
|
||||
|
||||
expect(nodes).toHaveLength(7)
|
||||
await nodes[2].trigger('click')
|
||||
expect(treeRef.getCheckedKeys().toString()).toBe(['1-1-1'].toString())
|
||||
await nodes[3].trigger('click')
|
||||
expect(nodes).toHaveLength(7)
|
||||
expect(treeRef.getCheckedKeys().toString()).toBe(
|
||||
['1-1-1', '1-1-2', '1-1'].toString()
|
||||
)
|
||||
})
|
||||
|
||||
test('showCheckbox :checkOnClickLeaf="false"', async () => {
|
||||
const { wrapper, treeRef } = createTree({
|
||||
data() {
|
||||
return {
|
||||
showCheckbox: true,
|
||||
checkOnClickLeaf: false,
|
||||
height: 400,
|
||||
data: [
|
||||
{
|
||||
id: '1',
|
||||
label: 'node-1',
|
||||
children: [
|
||||
{
|
||||
id: '1-1',
|
||||
label: 'node-1-1',
|
||||
children: [
|
||||
{
|
||||
id: '1-1-1',
|
||||
label: 'node-1-1-1',
|
||||
},
|
||||
{
|
||||
id: '1-1-2',
|
||||
label: 'node-1-1-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1-2',
|
||||
label: 'node-1-2',
|
||||
children: [
|
||||
{
|
||||
id: '1-2-1',
|
||||
label: 'node-1-2-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '1-3',
|
||||
label: 'node-1-3',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: 'node-2',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
})
|
||||
await nextTick()
|
||||
expect(treeRef.getCheckedKeys()).toHaveLength(0)
|
||||
let nodes = wrapper.findAll(TREE_NODE_CLASS_NAME)
|
||||
await nodes[0].trigger('click')
|
||||
nodes = wrapper.findAll(TREE_NODE_CLASS_NAME)
|
||||
await nodes[1].trigger('click')
|
||||
nodes = wrapper.findAll(TREE_NODE_CLASS_NAME)
|
||||
|
||||
expect(nodes).toHaveLength(7)
|
||||
await nodes[2].trigger('click')
|
||||
expect(treeRef.getCheckedKeys()).toHaveLength(0)
|
||||
})
|
||||
|
||||
test('defaultCheckedKeys', async () => {
|
||||
const { treeRef } = createTree({
|
||||
data() {
|
||||
|
@ -216,7 +216,11 @@ export function useTree(
|
||||
if (props.expandOnClickNode) {
|
||||
toggleExpand(node)
|
||||
}
|
||||
if (props.showCheckbox && props.checkOnClickNode && !node.disabled) {
|
||||
if (
|
||||
props.showCheckbox &&
|
||||
(props.checkOnClickNode || (node.isLeaf && props.checkOnClickLeaf)) &&
|
||||
!node.disabled
|
||||
) {
|
||||
toggleCheckbox(node, !isChecked(node), true)
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +107,10 @@ export const treeProps = buildProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
checkOnClickLeaf: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
currentNodeKey: {
|
||||
type: definePropType<TreeKey>([String, Number]),
|
||||
},
|
||||
|
@ -542,6 +542,42 @@ describe('Tree.vue', () => {
|
||||
expect(args.checkedNodes.length).toEqual(3)
|
||||
})
|
||||
|
||||
test('check by clicking on leaf node', async () => {
|
||||
const { wrapper } = getTreeVm(`:props="defaultProps" show-checkbox`)
|
||||
const treeVm = wrapper.findComponent(Tree).vm
|
||||
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
|
||||
const secondTreeNodeWrapper = wrapper.findAll('.el-tree-node')[2]
|
||||
await secondTreeNodeWrapper.trigger('click')
|
||||
|
||||
const secondNodeContentWrapper = secondTreeNodeWrapper.findAll(
|
||||
'.el-tree-node__content'
|
||||
)[1]
|
||||
await secondNodeContentWrapper.trigger('click')
|
||||
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(1)
|
||||
})
|
||||
|
||||
test('show-checkbox :check-on-click-leaf="false"', async () => {
|
||||
const { wrapper } = getTreeVm(
|
||||
`:props="defaultProps" show-checkbox :check-on-click-leaf="false"`
|
||||
)
|
||||
const treeVm = wrapper.findComponent(Tree).vm
|
||||
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
|
||||
const secondTreeNodeWrapper = wrapper.findAll('.el-tree-node')[2]
|
||||
await secondTreeNodeWrapper.trigger('click')
|
||||
|
||||
const secondNodeContentWrapper = secondTreeNodeWrapper.findAll(
|
||||
'.el-tree-node__content'
|
||||
)[1]
|
||||
await secondNodeContentWrapper.trigger('click')
|
||||
|
||||
expect(treeVm.getCheckedNodes().length).toEqual(0)
|
||||
})
|
||||
|
||||
test('setCheckedNodes', async () => {
|
||||
const { wrapper } = getTreeVm(
|
||||
`:props="defaultProps" show-checkbox node-key="id"`
|
||||
|
@ -247,7 +247,11 @@ export default defineComponent({
|
||||
handleExpandIconClick()
|
||||
}
|
||||
|
||||
if (tree.props.checkOnClickNode && !props.node.disabled) {
|
||||
if (
|
||||
(tree.props.checkOnClickNode ||
|
||||
(props.node.isLeaf && tree.props.checkOnClickLeaf)) &&
|
||||
!props.node.disabled
|
||||
) {
|
||||
handleCheckChange(!props.node.checked)
|
||||
}
|
||||
tree.ctx.emit('node-click', props.node.data, props.node, instance, e)
|
||||
|
@ -104,6 +104,7 @@ export interface TreeComponentProps {
|
||||
expandOnClickNode: boolean
|
||||
defaultExpandAll: boolean
|
||||
checkOnClickNode: boolean
|
||||
checkOnClickLeaf: boolean
|
||||
checkDescendants: boolean
|
||||
autoExpandParent: boolean
|
||||
defaultCheckedKeys: TreeKey[]
|
||||
|
@ -90,6 +90,10 @@ export default defineComponent({
|
||||
default: true,
|
||||
},
|
||||
checkOnClickNode: Boolean,
|
||||
checkOnClickLeaf: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
checkDescendants: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
|
Loading…
x
Reference in New Issue
Block a user