fix(components): [table] revert 20210 (#21482)

* fix(components): [table] revert 20210

* chore: update

* test: check indent
This commit is contained in:
btea
2025-07-24 20:04:31 +08:00
committed by GitHub
parent 283fa72bc9
commit 865ce3849e
7 changed files with 27 additions and 159 deletions

View File

@@ -282,7 +282,7 @@ table/tooltip-formatter
| row-key | key of row data, used for optimizing rendering. Required if `reserve-selection` is on or display tree data. When its type is String, multi-level access is supported, e.g. `user.info.id`, but `user.info[0].id` is not supported, in which case `Function` should be used | ^[function]`(row: any) => string` / ^[string] | — |
| empty-text | displayed text when data is empty. You can customize this area with `#empty` | ^[string] | No Data |
| default-expand-all | whether expand all rows by default, works when the table has a column type="expand" or contains tree structure data | ^[boolean] | false |
| expand-row-keys | set expanded rows by this prop, prop's value is the keys of expand rows, you should set row-key before using this prop. starting from version ^(2.10.3), keys of type number are supported. | ^[object]`Array<string \| number>` | — |
| expand-row-keys | set expanded rows by this prop, prop's value is the keys of expand rows, you should set row-key before using this prop. | ^[object]`Array<string>` | — |
| default-sort | set the default sort column and order. property `prop` is used to set default sort column, property `order` is used to set default sort order | ^[object]`Sort` | if `prop` is set, and `order` is not set, then `order` is default to ascending |
| tooltip-effect | the `effect` of the overflow tooltip | ^[enum]`'dark' \| 'light'` | dark |
| tooltip-options ^(2.2.28) | the options for the overflow tooltip, [see the following tooltip component](tooltip.html#attributes) | ^[object]`Pick<ElTooltipProps, 'effect' \| 'enterable' \| 'hideAfter' \| 'offset' \| 'placement' \| 'popperClass' \| 'popperOptions' \| 'showAfter' \| 'showArrow'>` | ^[object]`{ enterable: true, placement: 'top', showArrow: true, hideAfter: 200, popperOptions: { strategy: 'fixed' } }` |

View File

@@ -63,79 +63,6 @@ export function getTestData() {
]
}
export function getTestDataNumAndString() {
return [
{
id: 1,
test: {
id: 1,
},
name: 'Toy Story',
release: '1995-11-22',
director: 'John Lasseter',
runtime: 80,
},
{
id: 2,
test: {
id: 2,
},
name: 'Toy Story 2',
release: '1999-11-24',
director: 'John Lasseter',
runtime: 92,
children: [
{
id: 21,
test: {
id: 21,
},
key: '2asdf-21',
name: 'Toy Story 2',
release: '1999-11-24',
director: 'John Lasseter',
runtime: 92,
},
],
},
{
id: 3,
test: {
id: 3,
},
name: 'Monsters, Inc.',
release: '2001-11-2',
director: 'Peter Docter',
runtime: 92,
children: [
{
id: '31',
test: {
id: '31',
},
name: 'Monsters, Inc.',
release: '2001-11-2',
director: 'Peter Docter',
runtime: 92,
children: [
{
id: 311,
test: {
id: 311,
},
key: '2asdf-21',
name: 'Toy Story 2',
release: '1999-11-24',
director: 'John Lasseter',
runtime: 92,
},
],
},
],
},
]
}
export function getMultiRowTestData() {
return [
{

View File

@@ -11,7 +11,6 @@ import {
doubleWait,
getMultiRowTestData,
getTestData,
getTestDataNumAndString,
mount,
} from './table-test-common'
@@ -1722,6 +1721,14 @@ describe('Table.vue', () => {
expect(wrapper.findAll('.el-table__row').length).toEqual(8)
expect(spy.mock.calls[0][0]).toBeInstanceOf(Object)
expect(spy.mock.calls[0][1]).toBeTruthy()
const iconTr = expandIcon.element.closest('tr')
expect(iconTr.classList).toContain('el-table__row--level-0')
const firstChildRow = iconTr.nextElementSibling
expect(firstChildRow.classList).toContain('el-table__row--level-1')
const indent = firstChildRow.querySelector('.el-table__indent')
expect(indent).toBeTruthy()
expect(indent.style.paddingLeft).toEqual('16px')
})
it('tree-props & default-expand-all with dynamic data', async () => {
@@ -1948,72 +1955,6 @@ describe('Table.vue', () => {
)
})
it('expand-row-keys number and string', async () => {
wrapper = mount({
components: {
ElTable,
ElTableColumn,
},
template: `
<el-table :data="testData" row-key="id" :expand-row-keys="[2, 3, '31']">
<el-table-column prop="name" label="片名" />
<el-table-column prop="release" label="发行日期" />
<el-table-column prop="director" label="导演" />
<el-table-column prop="runtime" label="时长(分)" />
</el-table>
`,
data() {
return {
testData: getTestDataNumAndString(),
}
},
})
await doubleWait()
// 查找所有 level-1 的行
const level1Rows = wrapper.findAll('.el-table__row--level-1')
// 遍历每一行并检查其样式是否不为 display: none;
level1Rows.forEach((row) => {
const rowStyle = row.attributes('style')
if (rowStyle) {
expect(rowStyle).not.toContain('display: none;') // 期望样式不包含 display: none;
}
})
})
it('expand-row-keys multi-level number and string', async () => {
wrapper = mount({
components: {
ElTable,
ElTableColumn,
},
template: `
<el-table :data="testData" row-key="test.id" :expand-row-keys="[2, 3, '31']">
<el-table-column prop="name" label="片名" />
<el-table-column prop="release" label="发行日期" />
<el-table-column prop="director" label="导演" />
<el-table-column prop="runtime" label="时长(分)" />
</el-table>
`,
data() {
return {
testData: getTestDataNumAndString(),
}
},
})
await doubleWait()
// 查找所有 level-1 的行
const level1Rows = wrapper.findAll('.el-table__row--level-1')
// 遍历每一行并检查其样式是否不为 display: none;
level1Rows.forEach((row) => {
const rowStyle = row.attributes('style')
if (rowStyle) {
expect(rowStyle).not.toContain('display: none;') // 期望样式不包含 display: none;
}
})
})
it('v-if on el-table-column should patch correctly', async () => {
wrapper = mount({
components: {

View File

@@ -12,7 +12,7 @@ export interface TreeData extends TreeNode {
}
function useTree<T extends DefaultRow>(watcherData: WatcherPropsData<T>) {
const expandRowKeys = ref<Array<string | number>>([])
const expandRowKeys = ref<Array<string>>([])
const treeData = ref<Record<string, TreeData>>({})
const indent = ref(16)
const lazy = ref(false)
@@ -49,23 +49,23 @@ function useTree<T extends DefaultRow>(watcherData: WatcherPropsData<T>) {
const normalize = (data: T[]) => {
const rowKey = watcherData.rowKey.value
const res = new Map<string | number, TreeData>() // 使用 Map 替代 Object解决 number key 的问题
const res = {} as Record<string, TreeData>
walkTreeNode(
data,
(parent, children, level) => {
const parentId = getRowIdentity(parent, rowKey, true)
const parentId = getRowIdentity(parent, rowKey)
if (isArray(children)) {
res.set(parentId, {
children: children.map((row) => row[rowKey!]),
res[parentId] = {
children: children.map((row) => getRowIdentity(row, rowKey)),
level,
})
}
} else if (lazy.value) {
// 当 children 不存在且 lazy 为 true该节点即为懒加载的节点
res.set(parentId, {
res[parentId] = {
children: [],
lazy: true,
level,
})
}
}
},
childrenColumnName.value,
@@ -82,8 +82,9 @@ function useTree<T extends DefaultRow>(watcherData: WatcherPropsData<T>) {
ifExpandAll ||= instance.store?.states.defaultExpandAll.value
const nested = normalizedData.value
const normalizedLazyNode_ = normalizedLazyNode.value
const keys = Object.keys(nested)
const newTreeData: Record<string, TreeData> = {}
if (nested instanceof Map && nested.size) {
if (keys.length) {
const oldTreeData = unref(treeData)
const rootLazyRowKeys: string[] = []
const getExpanded = (oldValue: TreeData, key: string) => {
@@ -101,9 +102,9 @@ function useTree<T extends DefaultRow>(watcherData: WatcherPropsData<T>) {
}
}
// 合并 expanded 与 display确保数据刷新后状态不变
nested.forEach((_, key) => {
keys.forEach((key) => {
const oldValue = oldTreeData[key]
const newValue = { ...nested.get(key) }
const newValue = { ...nested[key] }
newValue.expanded = getExpanded(oldValue, key)
if (newValue.lazy) {
const { loaded = false, loading = false } = oldValue || {}
@@ -163,7 +164,7 @@ function useTree<T extends DefaultRow>(watcherData: WatcherPropsData<T>) {
}
)
const updateTreeExpandKeys = (value: (string | number)[]) => {
const updateTreeExpandKeys = (value: string[]) => {
expandRowKeys.value = value
updateTreeData()
}

View File

@@ -508,7 +508,7 @@ function useWatcher<T extends DefaultRow>() {
rowKey,
})
// 适配层expand-row-keys 在 Expand 与 TreeTable 中都有使用
const setExpandRowKeysAdapter = (val: (string | number)[]) => {
const setExpandRowKeysAdapter = (val: string[]) => {
// 这里会触发额外的计算,但为了兼容性,暂时这么做
setExpandRowKeys(val)
updateTreeExpandKeys(val)

View File

@@ -129,7 +129,7 @@ interface TableProps<T extends DefaultRow> {
highlightCurrentRow?: boolean
currentRowKey?: string | number
emptyText?: string
expandRowKeys?: Array<string | number>
expandRowKeys?: Array<string>
defaultExpandAll?: boolean
defaultSort?: Sort
tooltipEffect?: string

View File

@@ -182,13 +182,12 @@ export const getColumnByCell = function <T extends DefaultRow>(
export const getRowIdentity = <T extends DefaultRow>(
row: T,
rowKey: string | ((row: T) => string) | null,
isReturnRawValue: boolean = false
rowKey: string | ((row: T) => string) | null
): string => {
if (!row) throw new Error('Row is required when get row identity')
if (isString(rowKey)) {
if (!rowKey.includes('.')) {
return isReturnRawValue ? row[rowKey] : `${row[rowKey]}`
return `${row[rowKey]}`
}
const key = rowKey.split('.')
let current: any = row
@@ -197,7 +196,7 @@ export const getRowIdentity = <T extends DefaultRow>(
}
//TODO: "current" is now any, we just satisfies typecheck here
// but this function can actually return a number
return isReturnRawValue ? (current as string) : `${current}`
return `${current}`
} else if (isFunction(rowKey)) {
return rowKey.call(null, row)
}