以element-plus 低版本为例 低版本table中 固定列的实现是通过多个表格覆盖实现的,如果数据量大,表格会非常卡,新版本table采用sticky实现 这里通过修改源码实现低版本升级sticky形式
移出模版部分固定列代码
<div
v-if="store.states.fixedColumns.value.length > 0"
ref="fixedWrapper"
v-mousewheel="handleFixedMousewheel"
:style="[
{
width: layout.fixedWidth.value ? layout.fixedWidth.value + 'px' : ''
},
fixedHeight
]"
class="el-table__fixed"
>
// .....
<div
v-if="store.states.rightFixedColumns.value.length > 0"
ref="rightFixedPatch"
:style="{
width: layout.scrollY.value ? layout.gutterWidth + 'px' : '0',
height: layout.headerHeight.value + 'px'
}"
class="el-table__fixed-right-patch"
></div>
添加计算固定列的工具函数代码
在util文件中添加工具代码,都是用来计算是否是固定列的
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,
store: any,
realColumns?: TableColumnCtx<T>[]
) => {
let start = 0
let after = index
const columns = store.states.columns.value
if (realColumns) {
// 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
switch (fixed) {
case 'left':
if (after < store.states.fixedLeafColumnsLength.value) {
fixedLayout = 'left'
}
break
case 'right':
if (
start >=
columns.length - store.states.rightFixedLeafColumnsLength.value
) {
fixedLayout = 'right'
}
break
default:
if (after < store.states.fixedLeafColumnsLength.value) {
fixedLayout = 'left'
} else if (
start >=
columns.length - store.states.rightFixedLeafColumnsLength.value
) {
fixedLayout = 'right'
}
}
return fixedLayout
? {
direction: fixedLayout,
start,
after,
}
: {}
}
export const getFixedColumnsClass = <T>(
index: number,
fixed: string | boolean,
store: any,
realColumns?: TableColumnCtx<T>[],
offset = 0
) => {
const classes: string[] = []
const { direction, start, after } = isFixedColumn(
index,
fixed,
store,
realColumns
)
if (direction) {
const isLeft = direction === 'left'
classes.push(`fixed-column--${direction}`)
if (
isLeft &&
// @ts-ignore
after + offset === store.states.fixedLeafColumnsLength.value - 1
) {
classes.push('is-last-column')
} else if (
!isLeft &&
// @ts-ignore
start - offset ===
store.states.columns.value.length -
store.states.rightFixedLeafColumnsLength.value
) {
classes.push('is-first-column')
}
}
return classes
}
function getOffset<T>(offset: number, column: TableColumnCtx<T>) {
return (
offset +
(column.realWidth === null || Number.isNaN(column.realWidth)
? Number(column.width)
: column.realWidth)
)
}
export const getFixedColumnOffset = <T>(
index: number,
fixed: string | boolean,
store: any,
realColumns?: TableColumnCtx<T>[]
) => {
const {
direction,
start = 0,
after = 0,
} = isFixedColumn(index, fixed, store, realColumns)
if (!direction) {
return
}
const styles: any = {}
const isLeft = direction === 'left'
const columns = store.states.columns.value
if (isLeft) {
styles.left = columns.slice(0, start).reduce(getOffset, 0)
} else {
styles.right = columns
.slice(after + 1)
.reverse()
.reduce(getOffset, 0)
}
return styles
}
export const ensurePosition = (style, key: string) => {
if (!style) return
if (!Number.isNaN(style[key])) {
style[key] = `${style[key]}px`
}
}
分别修改style.hepler.ts
分别修改header、footer、cell等部分的style.helper.ts文件
table-header
table-body
table-footer
if (isCellHidden(cellIndex, store.states.columns.value, column)) {
classes.push(...
getFixedColumnsClass(cellIndex, column.fixed, props.store)
)
}
/table/src/table-body/render-helper.ts
CellClass部分多传递一个参数
原来模板的样式只覆盖到了body部分,导致滚动时,样式不能覆盖header,所以这里增加同步修改headerWrapper的className
覆盖部分样式
样式部分需要做一下覆盖 这里左右固定列的class可以自定义,需要同步修改util中的类名
$shadowLeft: inset 10px 0 10px -10px rgba(0, 0, 0, .15)!important;
$shadowRight: inset -10px 0 10px -10px rgba(0, 0, 0, .15)!important;
.el-table {
.fixed-column--left {
position: sticky !important;
background: inherit;
z-index: 2;
left: 0;
}
.fixed-column--right {
position: sticky !important;
background: inherit;
z-index: 2;
right: 0;
}
.el-table__body-wrapper,
.el-table__header-wrapper,
.el-table__footer-wrapper {
width: 100%;
tr {
td,
th {
overflow: unset!important;
&.fixed-column--left,
&.fixed-column--right {
position: sticky !important;
z-index: 2;
// background: getCssVar('bg-color');
&.is-last-column,
&.is-first-column {
&::before {
content: '';
position: absolute;
top: 0px;
width: 10px;
bottom: -1px;
overflow-x: hidden;
overflow-y: hidden;
box-shadow: none;
touch-action: none;
pointer-events: none;
}
}
&.is-first-column {
&::before {
left: -10px;
}
}
&.is-last-column {
&::before {
right: -10px;
box-shadow: none;
}
}
}
}
}
}
.is-scrolling-right {
.fixed-column--left.is-last-column {
&::before {
box-shadow: $shadowLeft;
}
}
.fixed-column--left.is-last-column {
border-right-color: transparent;
}
}
.is-scrolling-middle {
.fixed-column--left.is-last-column {
border-right-color: transparent;
}
.fixed-column--right.is-first-column {
&::before {
box-shadow: $shadowRight;
}
}
.fixed-column--left.is-last-column {
&::before {
box-shadow: $shadowLeft;
}
}
}
.is-scrolling-none {
.fixed-column--left,
.fixed-column--right {
&.is-first-column,
&.is-last-column {
&::before {
box-shadow: none;
}
}
}
th.fixed-column--left,
th.fixed-column--right {
background-color: getCssVar('header-bg-color');
}
}
}