fix(components): [table] fix children can't be unchecked (#20995)

* fix(components): [table] fix children can't be unchecked

* test(components): [table] reserve selection
This commit is contained in:
xiaohe0601
2025-06-20 10:01:20 +08:00
committed by GitHub
parent 4f56d01f04
commit 5cee7a1464
4 changed files with 149 additions and 7 deletions

View File

@@ -3,7 +3,12 @@ import { describe, expect, it, vi } from 'vitest'
import triggerEvent from '@element-plus/test-utils/trigger-event'
import ElTable from '../src/table.vue'
import ElTableColumn from '../src/table-column'
import { doubleWait, getTestData, mount } from './table-test-common'
import {
doubleWait,
getMutliRowTestData,
getTestData,
mount,
} from './table-test-common'
vi.mock('lodash-unified', async () => {
return {
@@ -424,6 +429,119 @@ describe('table column', () => {
selectionKeys = getSelection().map((item) => item.id)
expect(selectionKeys).toEqual([0, 1])
})
it('reserve selection', async () => {
const wrapper = mount({
components: {
ElTable,
ElTableColumn,
},
template: `
<el-table
:data="testData"
row-key="id"
default-expand-all
>
<el-table-column type="selection" reserve-selection />
<el-table-column prop="name" label="name" />
<el-table-column prop="release" label="release" />
<el-table-column prop="director" label="director" />
<el-table-column prop="runtime" label="runtime" />
</el-table>
`,
data() {
return { testData: [] }
},
created() {
this.updateTestData(1)
},
methods: {
getTestData(page) {
switch (page) {
case 1: {
const data = getTestData()
data[1].children = [
{
id: 21,
name: "A Bug's Life copy 1",
release: '1998-11-25-1',
director: 'John Lasseter',
runtime: 95,
},
{
id: 22,
name: "A Bug's Life copy 2",
release: '1998-11-25-2',
director: 'John Lasseter',
runtime: 95,
},
]
return data
}
case 2: {
return getMutliRowTestData()
}
}
return []
},
updateTestData(page) {
this.testData = this.getTestData(page)
},
},
})
await doubleWait()
wrapper.findAll('.el-checkbox')[1].trigger('click')
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(1)
expect(wrapper.findAll('.el-checkbox')[1].classes()).include(
'is-checked'
)
wrapper.vm.updateTestData(2)
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(0)
wrapper.vm.updateTestData(1)
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(1)
expect(wrapper.findAll('.el-checkbox')[1].classes()).include(
'is-checked'
)
wrapper.findAll('.el-checkbox')[1].trigger('click')
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(0)
// test children
wrapper.findAll('.el-checkbox')[3].trigger('click')
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(1)
expect(wrapper.findAll('.el-checkbox')[3].classes()).include(
'is-checked'
)
wrapper.vm.updateTestData(2)
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(0)
wrapper.vm.updateTestData(1)
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(1)
expect(wrapper.findAll('.el-checkbox')[3].classes()).include(
'is-checked'
)
// #20987
wrapper.findAll('.el-checkbox')[3].trigger('click')
await doubleWait()
expect(wrapper.findAll('.el-checkbox.is-checked')).toHaveLength(0)
wrapper.unmount()
})
})
describe('= index', () => {

View File

@@ -32,7 +32,15 @@ function useExpand<T>(watcherData: WatcherPropsData<T>) {
}
const toggleRowExpansion = (row: T, expanded?: boolean) => {
const changed = toggleRowStatus(expandRows.value, row, expanded)
const changed = toggleRowStatus(
expandRows.value,
row,
expanded,
undefined,
undefined,
undefined,
watcherData.rowKey.value
)
if (changed) {
instance.emit('expand-change', row, expandRows.value.slice())
}

View File

@@ -237,7 +237,8 @@ function useWatcher<T>() {
selected,
treeProps,
ignoreSelectable ? undefined : selectable.value,
data.value.indexOf(row)
data.value.indexOf(row),
rowKey.value
)
if (changed) {
const newSelection = (selection.value || []).slice()
@@ -275,7 +276,8 @@ function useWatcher<T>() {
value,
treeProps,
selectable.value,
rowIndex
rowIndex,
rowKey
)
) {
selectionChanged = true

View File

@@ -292,11 +292,24 @@ export function toggleRowStatus<T>(
newVal?: boolean,
tableTreeProps?: TreeProps,
selectable?: (row: T, index?: number) => boolean,
rowIndex?: number
rowIndex?: number,
rowKey?: string
): boolean {
let _rowIndex = rowIndex ?? 0
let changed = false
const index = statusArr.indexOf(row)
const getIndex = () => {
if (!rowKey) {
return statusArr.indexOf(row)
}
const id = getRowIdentity(row, rowKey)
return statusArr.findIndex((item) => getRowIdentity(item, rowKey) === id)
}
const index = getIndex()
const included = index !== -1
const isRowSelectable = selectable?.call(null, row, _rowIndex)
@@ -344,7 +357,8 @@ export function toggleRowStatus<T>(
newVal ?? !included,
tableTreeProps,
selectable,
_rowIndex + 1
_rowIndex + 1,
rowKey
)
_rowIndex += getChildrenCount(item) + 1
if (childChanged) {