mirror of
https://github.com/element-plus/element-plus.git
synced 2024-11-21 01:02:59 +08:00
fix(components): [el-tree-select] fix lazy and multiple select node (#17903)
* fix(components): [el-tree-select] fix lazy and multiple select node 1.Fix the issue where non-leaf nodes cannot be selected when using lazy and multiple together. 2. Since the original code did not handle the selection of non-leaf nodes before expanding lazy-loaded child nodes, additional processing was added to link the selection of parent and child nodes. 3. Because the time required for lazyLoad after nodeExpand cannot be predicted, the triggering time of the node-expand event in the tree has been adjusted to occur within the callback of the expand function. This change only affects the timing when using lazyLoad. BREAKING CHANGE : no closed closed Fixes #17232 * fix: test typecheck * fix: onNodeExpand event and update function name
This commit is contained in:
parent
93d28929fe
commit
27bdf1f076
@ -725,6 +725,63 @@ describe('TreeSelect.vue', () => {
|
||||
expect(modelValue.value).toEqual([])
|
||||
})
|
||||
|
||||
test('cached checked node and use lazy multiple', async () => {
|
||||
const modelValue = ref<number[]>([5])
|
||||
const cacheData = reactive([{ value: 5, label: 'lazy load node5' }])
|
||||
let id = 0
|
||||
const { tree, select } = createComponent({
|
||||
props: {
|
||||
modelValue,
|
||||
multiple: true,
|
||||
showCheckbox: true,
|
||||
checkStrictly: false,
|
||||
lazy: true,
|
||||
load: (node: object, resolve: (p: any) => any[]) => {
|
||||
resolve([
|
||||
{
|
||||
value: ++id,
|
||||
label: `lazy load node${id}`,
|
||||
},
|
||||
{
|
||||
value: ++id,
|
||||
label: `lazy load node${id}`,
|
||||
isLeaf: true,
|
||||
},
|
||||
])
|
||||
},
|
||||
cacheData,
|
||||
},
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
|
||||
const node1Checkbox = tree
|
||||
.findAll('.el-tree-node__content')[0]
|
||||
.find('.el-checkbox')
|
||||
await node1Checkbox.trigger('click')
|
||||
await nextTick()
|
||||
expect(select.vm.modelValue).toEqual([5, 1])
|
||||
|
||||
const node2Checkbox = tree
|
||||
.findAll('.el-tree-node__content')[1]
|
||||
.find('.el-checkbox')
|
||||
await node2Checkbox.trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(select.vm.modelValue).toEqual([5, 1, 2])
|
||||
|
||||
const node1 = tree.findAll('.el-tree-node__content')[0]
|
||||
await node1.trigger('click')
|
||||
await nextTick()
|
||||
expect(select.vm.modelValue).toEqual([5, 3, 4, 2])
|
||||
|
||||
const node2 = tree.findAll('.el-tree-node__content')[1]
|
||||
await node2.trigger('click')
|
||||
await nextTick()
|
||||
|
||||
expect(select.vm.modelValue).toEqual([5, 6, 4, 2])
|
||||
})
|
||||
|
||||
test('no checkbox and check on click node', async () => {
|
||||
const { select, tree } = createComponent({
|
||||
props: {
|
||||
|
@ -1,8 +1,8 @@
|
||||
// @ts-nocheck
|
||||
import { computed, nextTick, toRefs, watch } from 'vue'
|
||||
import { isEqual, pick } from 'lodash-unified'
|
||||
import { isEqual, isNil, pick } from 'lodash-unified'
|
||||
import { UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
import { escapeStringRegexp, isFunction } from '@element-plus/utils'
|
||||
import { escapeStringRegexp, isEmpty, isFunction } from '@element-plus/utils'
|
||||
import ElTree from '@element-plus/components/tree'
|
||||
import TreeSelectOption from './tree-select-option'
|
||||
import {
|
||||
@ -113,6 +113,13 @@ export const useTree = (
|
||||
return options
|
||||
})
|
||||
|
||||
const getChildCheckedKeys = () => {
|
||||
return tree.value?.getCheckedKeys().filter((checkedKey) => {
|
||||
const node = tree.value?.getNode(checkedKey) as Node
|
||||
return !isNil(node) && isEmpty(node.childNodes)
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
...pick(toRefs(props), Object.keys(ElTree.props)),
|
||||
...attrs,
|
||||
@ -208,10 +215,9 @@ export const useTree = (
|
||||
// only can select leaf node
|
||||
else {
|
||||
if (props.multiple) {
|
||||
emit(
|
||||
UPDATE_MODEL_EVENT,
|
||||
cachedKeys.concat((tree.value as TreeInstance).getCheckedKeys(true))
|
||||
)
|
||||
const childKeys = getChildCheckedKeys()
|
||||
|
||||
emit(UPDATE_MODEL_EVENT, cachedKeys.concat(childKeys))
|
||||
} else {
|
||||
// select first leaf node when check parent
|
||||
const firstLeaf = treeFind(
|
||||
@ -258,6 +264,35 @@ export const useTree = (
|
||||
select.value?.focus()
|
||||
},
|
||||
|
||||
onNodeExpand: (data, node, e) => {
|
||||
attrs.onNodeExpand?.(data, node, e)
|
||||
nextTick(() => {
|
||||
if (
|
||||
!props.checkStrictly &&
|
||||
props.lazy &&
|
||||
props.multiple &&
|
||||
node.checked
|
||||
) {
|
||||
const dataMap = {}
|
||||
const uncachedCheckedKeys = (
|
||||
tree.value as TreeInstance
|
||||
).getCheckedKeys()
|
||||
|
||||
treeEach(
|
||||
[tree.value.store.root],
|
||||
(node) => (dataMap[node.key] = node),
|
||||
(node) => node.childNodes
|
||||
)
|
||||
|
||||
const cachedKeys = toValidArray(props.modelValue).filter(
|
||||
(item) => !(item in dataMap) && !uncachedCheckedKeys.includes(item)
|
||||
)
|
||||
|
||||
const childKeys = getChildCheckedKeys()
|
||||
emit(UPDATE_MODEL_EVENT, cachedKeys.concat(childKeys))
|
||||
}
|
||||
})
|
||||
},
|
||||
// else
|
||||
cacheOptions,
|
||||
}
|
||||
|
@ -270,8 +270,9 @@ export default defineComponent({
|
||||
tree.ctx.emit('node-collapse', props.node.data, props.node, instance)
|
||||
props.node.collapse()
|
||||
} else {
|
||||
props.node.expand()
|
||||
props.node.expand(() => {
|
||||
ctx.emit('node-expand', props.node.data, props.node, instance)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user