mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 04:08:34 +08:00
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:
parent
dec859a3df
commit
9285109a0c
@ -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 row selection is supported.
|
||||
|
73
docs/examples/table/fixed-column-and-group-header.vue
Normal file
73
docs/examples/table/fixed-column-and-group-header.vue
Normal 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>
|
@ -701,6 +701,68 @@ describe('table column', () => {
|
||||
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 () => {
|
||||
const TableColumn = {
|
||||
name: 'TableColumn',
|
||||
|
@ -84,8 +84,19 @@ function useWatcher<T>() {
|
||||
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 = () => {
|
||||
_columns.value.forEach((column) => {
|
||||
updateChildFixed(column)
|
||||
})
|
||||
fixedColumns.value = _columns.value.filter(
|
||||
(column) => column.fixed === true || column.fixed === 'left'
|
||||
)
|
||||
|
@ -67,9 +67,11 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
|
||||
column,
|
||||
})
|
||||
}
|
||||
const fixedStyle = column.isSubColumn
|
||||
? null
|
||||
: getFixedColumnOffset(columnIndex, props?.fixed, props.store)
|
||||
const fixedStyle = getFixedColumnOffset(
|
||||
columnIndex,
|
||||
props?.fixed,
|
||||
props.store
|
||||
)
|
||||
ensurePosition(fixedStyle, 'left')
|
||||
ensurePosition(fixedStyle, 'right')
|
||||
return Object.assign({}, cellStyles, fixedStyle)
|
||||
@ -82,16 +84,14 @@ function useStyles<T>(props: Partial<TableBodyProps<T>>) {
|
||||
column: TableColumnCtx<T>,
|
||||
offset: number
|
||||
) => {
|
||||
const fixedClasses = column.isSubColumn
|
||||
? []
|
||||
: getFixedColumnsClass(
|
||||
ns.b(),
|
||||
columnIndex,
|
||||
props?.fixed,
|
||||
props.store,
|
||||
undefined,
|
||||
offset
|
||||
)
|
||||
const fixedClasses = getFixedColumnsClass(
|
||||
ns.b(),
|
||||
columnIndex,
|
||||
props?.fixed,
|
||||
props.store,
|
||||
undefined,
|
||||
offset
|
||||
)
|
||||
const classes = [column.id, column.align, column.className, ...fixedClasses]
|
||||
const cellClassName = parent?.props.cellClassName
|
||||
if (typeof cellClassName === 'string') {
|
||||
|
@ -48,14 +48,12 @@ function useStyle<T>(props: TableHeaderProps<T>) {
|
||||
column,
|
||||
})
|
||||
}
|
||||
const fixedStyle = column.isSubColumn
|
||||
? null
|
||||
: getFixedColumnOffset<T>(
|
||||
columnIndex,
|
||||
column.fixed,
|
||||
props.store,
|
||||
row as unknown as TableColumnCtx<T>[]
|
||||
)
|
||||
const fixedStyle = getFixedColumnOffset<T>(
|
||||
columnIndex,
|
||||
column.fixed,
|
||||
props.store,
|
||||
row as unknown as TableColumnCtx<T>[]
|
||||
)
|
||||
ensurePosition(fixedStyle, 'left')
|
||||
ensurePosition(fixedStyle, 'right')
|
||||
return Object.assign({}, headerCellStyles, fixedStyle)
|
||||
@ -67,15 +65,13 @@ function useStyle<T>(props: TableHeaderProps<T>) {
|
||||
row: T,
|
||||
column: TableColumnCtx<T>
|
||||
) => {
|
||||
const fixedClasses = column.isSubColumn
|
||||
? []
|
||||
: getFixedColumnsClass<T>(
|
||||
ns.b(),
|
||||
columnIndex,
|
||||
column.fixed,
|
||||
props.store,
|
||||
row as unknown as TableColumnCtx<T>[]
|
||||
)
|
||||
const fixedClasses = getFixedColumnsClass<T>(
|
||||
ns.b(),
|
||||
columnIndex,
|
||||
column.fixed,
|
||||
props.store,
|
||||
row as unknown as TableColumnCtx<T>[]
|
||||
)
|
||||
const classes = [
|
||||
column.id,
|
||||
column.order,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { createPopper } from '@popperjs/core'
|
||||
import { get } from 'lodash-unified'
|
||||
import { flatMap, get } from 'lodash-unified'
|
||||
import escapeHtml from 'escape-html'
|
||||
import { hasOwn, throwError } from '@element-plus/utils'
|
||||
import { useZIndex } from '@element-plus/hooks'
|
||||
@ -379,6 +379,18 @@ export function createTablePopper(
|
||||
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>(
|
||||
index: number,
|
||||
fixed: string | boolean,
|
||||
@ -387,21 +399,18 @@ export const isFixedColumn = <T>(
|
||||
) => {
|
||||
let start = 0
|
||||
let after = index
|
||||
const columns = store.states.columns.value
|
||||
if (realColumns) {
|
||||
if (realColumns[index].colSpan > 1) {
|
||||
// fixed column not supported in grouped header
|
||||
return {}
|
||||
}
|
||||
// handle group
|
||||
for (let i = 0; i < index; i++) {
|
||||
start += realColumns[i].colSpan
|
||||
}
|
||||
after = start + realColumns[index].colSpan - 1
|
||||
// fixed column supported in grouped header
|
||||
const curColumns = getCurrentColumns(realColumns[index])
|
||||
const preColumns = columns.slice(0, columns.indexOf(curColumns[0]))
|
||||
|
||||
start = preColumns.reduce(getColSpan, 0)
|
||||
after = start + curColumns.reduce(getColSpan, 0) - 1
|
||||
} else {
|
||||
start = index
|
||||
}
|
||||
let fixedLayout
|
||||
const columns = store.states.columns
|
||||
switch (fixed) {
|
||||
case 'left':
|
||||
if (after < store.states.fixedLeafColumnsLength.value) {
|
||||
@ -411,7 +420,7 @@ export const isFixedColumn = <T>(
|
||||
case 'right':
|
||||
if (
|
||||
start >=
|
||||
columns.value.length - store.states.rightFixedLeafColumnsLength.value
|
||||
columns.length - store.states.rightFixedLeafColumnsLength.value
|
||||
) {
|
||||
fixedLayout = 'right'
|
||||
}
|
||||
@ -421,7 +430,7 @@ export const isFixedColumn = <T>(
|
||||
fixedLayout = 'left'
|
||||
} else if (
|
||||
start >=
|
||||
columns.value.length - store.states.rightFixedLeafColumnsLength.value
|
||||
columns.length - store.states.rightFixedLeafColumnsLength.value
|
||||
) {
|
||||
fixedLayout = 'right'
|
||||
}
|
||||
@ -444,13 +453,18 @@ export const getFixedColumnsClass = <T>(
|
||||
offset = 0
|
||||
) => {
|
||||
const classes: string[] = []
|
||||
const { direction, start } = isFixedColumn(index, fixed, store, realColumns)
|
||||
const { direction, start, after } = isFixedColumn(
|
||||
index,
|
||||
fixed,
|
||||
store,
|
||||
realColumns
|
||||
)
|
||||
if (direction) {
|
||||
const isLeft = direction === 'left'
|
||||
classes.push(`${namespace}-fixed-column--${direction}`)
|
||||
if (
|
||||
isLeft &&
|
||||
start + offset === store.states.fixedLeafColumnsLength.value - 1
|
||||
after + offset === store.states.fixedLeafColumnsLength.value - 1
|
||||
) {
|
||||
classes.push('is-last-column')
|
||||
} else if (
|
||||
@ -480,12 +494,11 @@ export const getFixedColumnOffset = <T>(
|
||||
store: any,
|
||||
realColumns?: TableColumnCtx<T>[]
|
||||
) => {
|
||||
const { direction, start = 0 } = isFixedColumn(
|
||||
index,
|
||||
fixed,
|
||||
store,
|
||||
realColumns
|
||||
)
|
||||
const {
|
||||
direction,
|
||||
start = 0,
|
||||
after = 0,
|
||||
} = isFixedColumn(index, fixed, store, realColumns)
|
||||
if (!direction) {
|
||||
return
|
||||
}
|
||||
@ -493,10 +506,10 @@ export const getFixedColumnOffset = <T>(
|
||||
const isLeft = direction === 'left'
|
||||
const columns = store.states.columns.value
|
||||
if (isLeft) {
|
||||
styles.left = columns.slice(0, index).reduce(getOffset, 0)
|
||||
styles.left = columns.slice(0, start).reduce(getOffset, 0)
|
||||
} else {
|
||||
styles.right = columns
|
||||
.slice(start + 1)
|
||||
.slice(after + 1)
|
||||
.reverse()
|
||||
.reduce(getOffset, 0)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user