fix(components): [table] fixed column supported in grouped header (#10096)

* fix(components): [table] fixed column supported in grouped header

* fix(components): [table] fixed column supported in grouped header

* fix(components): [table] fixed column supported in grouped header

* fix(components): [table] fixed column supported in grouped header
This commit is contained in:
tinyfind 2022-10-23 19:56:20 +08:00 committed by GitHub
parent dec859a3df
commit 9285109a0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 218 additions and 53 deletions

View File

@ -95,6 +95,16 @@ table/grouping-header
::: :::
## Table with fixed group header
fixed group head is supported
:::demo The attribute `fixed` of the group header is determined by the outermost `el-table-column`
table/fixed-column-and-group-header
:::
## Single select ## Single select
Single row selection is supported. Single row selection is supported.

View File

@ -0,0 +1,73 @@
<template>
<el-table :data="tableData" style="width: 100%" height="250">
<el-table-column prop="date" label="Date" width="150" />
<el-table-column prop="name" label="Name" width="150" />
<el-table-column prop="zip" label="Zip" width="150" />
<el-table-column label="Address Info" fixed="right">
<el-table-column prop="state" label="State" width="100" />
<el-table-column prop="city" label="City" width="120" />
<el-table-column prop="address" label="Address" width="250" />
</el-table-column>
</el-table>
</template>
<script lang="ts" setup>
const tableData = [
{
date: '2016-05-03',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
{
date: '2016-05-02',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
{
date: '2016-05-04',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
{
date: '2016-05-01',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
{
date: '2016-05-08',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
{
date: '2016-05-06',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
{
date: '2016-05-07',
name: 'Tom',
state: 'California',
city: 'Los Angeles',
address: 'No. 189, Grove St, Los Angeles',
zip: 'CA 90036',
},
]
</script>

View File

@ -701,6 +701,68 @@ describe('table column', () => {
wrapper.unmount() wrapper.unmount()
}) })
it('should work with fixed', async () => {
const wrapper = mount({
components: {
ElTable,
ElTableColumn,
},
template: `
<el-table :data="testData">
<el-table-column prop="name" />
<el-table-column label="group" fixed="left">
<el-table-column label="group's group">
<el-table-column prop="runtime" width="100" fixed="right"/>
<el-table-column prop="director" width="100" fixed="right"/>
</el-table-column>
<el-table-column prop="director"/>
</el-table-column>
<el-table-column prop="director"/>
<el-table-column prop="runtime"/>
<el-table-column label="group2" fixed="right">
<el-table-column prop="runtime" width="100" fixed="left"/>
<el-table-column prop="director" width="50"/>
</el-table-column>
<el-table-column prop="runtime"/>
</el-table>
`,
created() {
this.testData = getTestData()
},
})
await doubleWait()
const lfhcolumns = wrapper
.findAll('.el-table__header tr')
.map((item) => item.findAll('.el-table-fixed-column--left'))
const lfbcolumns = wrapper.findAll(
'.el-table__body .el-table-fixed-column--left'
)
const rfhcolumns = wrapper
.findAll('.el-table__header tr')
.map((item) => item.findAll('.el-table-fixed-column--right'))
const rfbcolumns = wrapper.findAll(
'.el-table__body .el-table-fixed-column--right'
)
expect(lfbcolumns).toHaveLength(15)
expect(rfbcolumns).toHaveLength(10)
expect(lfhcolumns.at(0).at(0).classes()).toContain('is-last-column')
expect(lfhcolumns.at(1).at(1).classes()).toContain('is-last-column')
expect(getComputedStyle(lfhcolumns.at(1).at(1).element).left).toBe(
'200px'
)
expect(getComputedStyle(lfhcolumns.at(2).at(1).element).left).toBe(
'100px'
)
expect(rfhcolumns.at(0).at(0).classes()).toContain('is-first-column')
expect(rfhcolumns.at(1).at(0).classes()).toContain('is-first-column')
expect(getComputedStyle(rfhcolumns.at(1).at(0).element).right).toBe(
'50px'
)
wrapper.unmount()
})
it('el-table-column should callback itself', async () => { it('el-table-column should callback itself', async () => {
const TableColumn = { const TableColumn = {
name: 'TableColumn', name: 'TableColumn',

View File

@ -84,8 +84,19 @@ function useWatcher<T>() {
if (!rowKey.value) throw new Error('[ElTable] prop row-key is required') if (!rowKey.value) throw new Error('[ElTable] prop row-key is required')
} }
// 更新 fixed
const updateChildFixed = (column: TableColumnCtx<T>) => {
column.children?.forEach((childColumn) => {
childColumn.fixed = column.fixed
updateChildFixed(childColumn)
})
}
// 更新列 // 更新列
const updateColumns = () => { const updateColumns = () => {
_columns.value.forEach((column) => {
updateChildFixed(column)
})
fixedColumns.value = _columns.value.filter( fixedColumns.value = _columns.value.filter(
(column) => column.fixed === true || column.fixed === 'left' (column) => column.fixed === true || column.fixed === 'left'
) )

View File

@ -67,9 +67,11 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
column, column,
}) })
} }
const fixedStyle = column.isSubColumn const fixedStyle = getFixedColumnOffset(
? null columnIndex,
: getFixedColumnOffset(columnIndex, props?.fixed, props.store) props?.fixed,
props.store
)
ensurePosition(fixedStyle, 'left') ensurePosition(fixedStyle, 'left')
ensurePosition(fixedStyle, 'right') ensurePosition(fixedStyle, 'right')
return Object.assign({}, cellStyles, fixedStyle) return Object.assign({}, cellStyles, fixedStyle)
@ -82,16 +84,14 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
column: TableColumnCtx<T>, column: TableColumnCtx<T>,
offset: number offset: number
) => { ) => {
const fixedClasses = column.isSubColumn const fixedClasses = getFixedColumnsClass(
? [] ns.b(),
: getFixedColumnsClass( columnIndex,
ns.b(), props?.fixed,
columnIndex, props.store,
props?.fixed, undefined,
props.store, offset
undefined, )
offset
)
const classes = [column.id, column.align, column.className, ...fixedClasses] const classes = [column.id, column.align, column.className, ...fixedClasses]
const cellClassName = parent?.props.cellClassName const cellClassName = parent?.props.cellClassName
if (typeof cellClassName === 'string') { if (typeof cellClassName === 'string') {

View File

@ -48,14 +48,12 @@ function useStyle<T>(props: TableHeaderProps<T>) {
column, column,
}) })
} }
const fixedStyle = column.isSubColumn const fixedStyle = getFixedColumnOffset<T>(
? null columnIndex,
: getFixedColumnOffset<T>( column.fixed,
columnIndex, props.store,
column.fixed, row as unknown as TableColumnCtx<T>[]
props.store, )
row as unknown as TableColumnCtx<T>[]
)
ensurePosition(fixedStyle, 'left') ensurePosition(fixedStyle, 'left')
ensurePosition(fixedStyle, 'right') ensurePosition(fixedStyle, 'right')
return Object.assign({}, headerCellStyles, fixedStyle) return Object.assign({}, headerCellStyles, fixedStyle)
@ -67,15 +65,13 @@ function useStyle<T>(props: TableHeaderProps<T>) {
row: T, row: T,
column: TableColumnCtx<T> column: TableColumnCtx<T>
) => { ) => {
const fixedClasses = column.isSubColumn const fixedClasses = getFixedColumnsClass<T>(
? [] ns.b(),
: getFixedColumnsClass<T>( columnIndex,
ns.b(), column.fixed,
columnIndex, props.store,
column.fixed, row as unknown as TableColumnCtx<T>[]
props.store, )
row as unknown as TableColumnCtx<T>[]
)
const classes = [ const classes = [
column.id, column.id,
column.order, column.order,

View File

@ -1,6 +1,6 @@
// @ts-nocheck // @ts-nocheck
import { createPopper } from '@popperjs/core' import { createPopper } from '@popperjs/core'
import { get } from 'lodash-unified' import { flatMap, get } from 'lodash-unified'
import escapeHtml from 'escape-html' import escapeHtml from 'escape-html'
import { hasOwn, throwError } from '@element-plus/utils' import { hasOwn, throwError } from '@element-plus/utils'
import { useZIndex } from '@element-plus/hooks' import { useZIndex } from '@element-plus/hooks'
@ -379,6 +379,18 @@ export function createTablePopper(
return popperInstance return popperInstance
} }
function getCurrentColumns<T>(column: TableColumnCtx<T>): TableColumnCtx<T>[] {
if (column.children) {
return flatMap(column.children, getCurrentColumns)
} else {
return [column]
}
}
function getColSpan<T>(colSpan: number, column: TableColumnCtx<T>) {
return colSpan + column.colSpan
}
export const isFixedColumn = <T>( export const isFixedColumn = <T>(
index: number, index: number,
fixed: string | boolean, fixed: string | boolean,
@ -387,21 +399,18 @@ export const isFixedColumn = <T>(
) => { ) => {
let start = 0 let start = 0
let after = index let after = index
const columns = store.states.columns.value
if (realColumns) { if (realColumns) {
if (realColumns[index].colSpan > 1) { // fixed column supported in grouped header
// fixed column not supported in grouped header const curColumns = getCurrentColumns(realColumns[index])
return {} const preColumns = columns.slice(0, columns.indexOf(curColumns[0]))
}
// handle group start = preColumns.reduce(getColSpan, 0)
for (let i = 0; i < index; i++) { after = start + curColumns.reduce(getColSpan, 0) - 1
start += realColumns[i].colSpan
}
after = start + realColumns[index].colSpan - 1
} else { } else {
start = index start = index
} }
let fixedLayout let fixedLayout
const columns = store.states.columns
switch (fixed) { switch (fixed) {
case 'left': case 'left':
if (after < store.states.fixedLeafColumnsLength.value) { if (after < store.states.fixedLeafColumnsLength.value) {
@ -411,7 +420,7 @@ export const isFixedColumn = <T>(
case 'right': case 'right':
if ( if (
start >= start >=
columns.value.length - store.states.rightFixedLeafColumnsLength.value columns.length - store.states.rightFixedLeafColumnsLength.value
) { ) {
fixedLayout = 'right' fixedLayout = 'right'
} }
@ -421,7 +430,7 @@ export const isFixedColumn = <T>(
fixedLayout = 'left' fixedLayout = 'left'
} else if ( } else if (
start >= start >=
columns.value.length - store.states.rightFixedLeafColumnsLength.value columns.length - store.states.rightFixedLeafColumnsLength.value
) { ) {
fixedLayout = 'right' fixedLayout = 'right'
} }
@ -444,13 +453,18 @@ export const getFixedColumnsClass = <T>(
offset = 0 offset = 0
) => { ) => {
const classes: string[] = [] const classes: string[] = []
const { direction, start } = isFixedColumn(index, fixed, store, realColumns) const { direction, start, after } = isFixedColumn(
index,
fixed,
store,
realColumns
)
if (direction) { if (direction) {
const isLeft = direction === 'left' const isLeft = direction === 'left'
classes.push(`${namespace}-fixed-column--${direction}`) classes.push(`${namespace}-fixed-column--${direction}`)
if ( if (
isLeft && isLeft &&
start + offset === store.states.fixedLeafColumnsLength.value - 1 after + offset === store.states.fixedLeafColumnsLength.value - 1
) { ) {
classes.push('is-last-column') classes.push('is-last-column')
} else if ( } else if (
@ -480,12 +494,11 @@ export const getFixedColumnOffset = <T>(
store: any, store: any,
realColumns?: TableColumnCtx<T>[] realColumns?: TableColumnCtx<T>[]
) => { ) => {
const { direction, start = 0 } = isFixedColumn( const {
index, direction,
fixed, start = 0,
store, after = 0,
realColumns } = isFixedColumn(index, fixed, store, realColumns)
)
if (!direction) { if (!direction) {
return return
} }
@ -493,10 +506,10 @@ export const getFixedColumnOffset = <T>(
const isLeft = direction === 'left' const isLeft = direction === 'left'
const columns = store.states.columns.value const columns = store.states.columns.value
if (isLeft) { if (isLeft) {
styles.left = columns.slice(0, index).reduce(getOffset, 0) styles.left = columns.slice(0, start).reduce(getOffset, 0)
} else { } else {
styles.right = columns styles.right = columns
.slice(start + 1) .slice(after + 1)
.reverse() .reverse()
.reduce(getOffset, 0) .reduce(getOffset, 0)
} }