diff --git a/docs/en-US/component/table.md b/docs/en-US/component/table.md
index 68de4e000c..94dee6835d 100644
--- a/docs/en-US/component/table.md
+++ b/docs/en-US/component/table.md
@@ -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.
diff --git a/docs/examples/table/fixed-column-and-group-header.vue b/docs/examples/table/fixed-column-and-group-header.vue
new file mode 100644
index 0000000000..5a812be535
--- /dev/null
+++ b/docs/examples/table/fixed-column-and-group-header.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/table/__tests__/table-column.test.ts b/packages/components/table/__tests__/table-column.test.ts
index 42896f3b34..69354fd513 100644
--- a/packages/components/table/__tests__/table-column.test.ts
+++ b/packages/components/table/__tests__/table-column.test.ts
@@ -701,6 +701,68 @@ describe('table column', () => {
wrapper.unmount()
})
+ it('should work with fixed', async () => {
+ const wrapper = mount({
+ components: {
+ ElTable,
+ ElTableColumn,
+ },
+ template: `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `,
+
+ 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',
diff --git a/packages/components/table/src/store/watcher.ts b/packages/components/table/src/store/watcher.ts
index b8621017ff..cf6ffdb3a0 100644
--- a/packages/components/table/src/store/watcher.ts
+++ b/packages/components/table/src/store/watcher.ts
@@ -84,8 +84,19 @@ function useWatcher() {
if (!rowKey.value) throw new Error('[ElTable] prop row-key is required')
}
+ // 更新 fixed
+ const updateChildFixed = (column: TableColumnCtx) => {
+ 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'
)
diff --git a/packages/components/table/src/table-body/styles-helper.ts b/packages/components/table/src/table-body/styles-helper.ts
index 2b52210001..1313c27d11 100644
--- a/packages/components/table/src/table-body/styles-helper.ts
+++ b/packages/components/table/src/table-body/styles-helper.ts
@@ -67,9 +67,11 @@ function useStyles(props: Partial>) {
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(props: Partial>) {
column: TableColumnCtx,
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') {
diff --git a/packages/components/table/src/table-header/style.helper.ts b/packages/components/table/src/table-header/style.helper.ts
index a81866b655..9df5745c92 100644
--- a/packages/components/table/src/table-header/style.helper.ts
+++ b/packages/components/table/src/table-header/style.helper.ts
@@ -48,14 +48,12 @@ function useStyle(props: TableHeaderProps) {
column,
})
}
- const fixedStyle = column.isSubColumn
- ? null
- : getFixedColumnOffset(
- columnIndex,
- column.fixed,
- props.store,
- row as unknown as TableColumnCtx[]
- )
+ const fixedStyle = getFixedColumnOffset(
+ columnIndex,
+ column.fixed,
+ props.store,
+ row as unknown as TableColumnCtx[]
+ )
ensurePosition(fixedStyle, 'left')
ensurePosition(fixedStyle, 'right')
return Object.assign({}, headerCellStyles, fixedStyle)
@@ -67,15 +65,13 @@ function useStyle(props: TableHeaderProps) {
row: T,
column: TableColumnCtx
) => {
- const fixedClasses = column.isSubColumn
- ? []
- : getFixedColumnsClass(
- ns.b(),
- columnIndex,
- column.fixed,
- props.store,
- row as unknown as TableColumnCtx[]
- )
+ const fixedClasses = getFixedColumnsClass(
+ ns.b(),
+ columnIndex,
+ column.fixed,
+ props.store,
+ row as unknown as TableColumnCtx[]
+ )
const classes = [
column.id,
column.order,
diff --git a/packages/components/table/src/util.ts b/packages/components/table/src/util.ts
index a0b3be1f2d..02c6e41945 100644
--- a/packages/components/table/src/util.ts
+++ b/packages/components/table/src/util.ts
@@ -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(column: TableColumnCtx): TableColumnCtx[] {
+ if (column.children) {
+ return flatMap(column.children, getCurrentColumns)
+ } else {
+ return [column]
+ }
+}
+
+function getColSpan(colSpan: number, column: TableColumnCtx) {
+ return colSpan + column.colSpan
+}
+
export const isFixedColumn = (
index: number,
fixed: string | boolean,
@@ -387,21 +399,18 @@ export const isFixedColumn = (
) => {
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 = (
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 = (
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 = (
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 = (
store: any,
realColumns?: TableColumnCtx[]
) => {
- 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 = (
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)
}