在账单管理、财务报表这类业务场景中,表格底部固定行几乎是刚需功能。Element UI的el-table组件提供了summary-method这个非常实用的属性,但官方文档只展示了最简单的单行求和场景。实际开发中,我们经常遇到更复杂的需求:
我最近在开发一个财务系统时就遇到了这样的需求:表格底部需要固定显示两行数据,第一行是当月汇总,第二行是年度累计,所有数据都需要从后端接口实时获取。经过多次尝试和优化,最终找到了一套比较完善的解决方案。
先回顾下summary-method的基础用法。假设我们有个简单的账单表格,需要在底部显示金额总和:
javascript复制<el-table
:data="tableData"
:summary-method="getSummaries"
show-summary>
<!-- 列定义 -->
</el-table>
methods: {
getSummaries({ columns, data }) {
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计'
return
}
const values = data.map(item => Number(item[column.property]))
if (!values.every(value => isNaN(value))) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr)
return isNaN(value) ? prev : prev + value
}, 0)
sums[index] += '元' // 添加单位
} else {
sums[index] = ''
}
})
return sums
}
}
这种实现有几个明显局限:
要实现多行固定且支持动态数据,关键在于两点:
javascript复制getSummaries(param) {
const { columns } = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '汇总'
return
}
if (index === 1) {
sums[index] = (
<div class="summary-row">
<div>本期合计</div>
<div>本年累计</div>
</div>
)
return
}
sums[index] = (
<div class="summary-row">
<div ref="currentAmount"></div>
<div ref="yearAmount"></div>
</div>
)
})
return sums
}
由于汇总行是动态生成的,直接操作DOM可能会遇到元素未渲染的问题。这里需要使用Vue的$nextTick确保DOM就绪:
javascript复制async fetchSummaryData() {
const res = await getSummaryData() // 调用API
this.summaryData = res.data
this.$nextTick(() => {
this.$refs.currentAmount.innerHTML = this.formatCurrency(this.summaryData.current)
this.$refs.yearAmount.innerHTML = this.formatCurrency(this.summaryData.year)
})
}
实际项目中,我发现在某些情况下还需要加个setTimeout保证稳定性:
javascript复制setTimeout(() => {
this.$nextTick(() => {
// 更新refs
})
}, 50)
在财务表格中,不同列可能需要不同的处理方式:
javascript复制columns.forEach((column, index) => {
// 第一列固定文本
if (index === 0) {
sums[index] = '汇总'
return
}
// 金额列特殊处理
if (['income', 'expense'].includes(column.property)) {
sums[index] = (
<div class="money-column">
<div ref={`${column.property}Current`}></div>
<div ref={`${column.property}Year`}></div>
</div>
)
return
}
// 状态列特殊处理
if (column.property === 'status') {
sums[index] = (
<div class="status-column">
<el-tag ref="currentStatus"></el-tag>
<el-tag ref="yearStatus"></el-tag>
</div>
)
return
}
})
多行汇总容易导致样式混乱,需要特别注意CSS控制:
css复制.summary-row {
display: flex;
flex-direction: column;
line-height: 30px;
}
.money-column {
text-align: right;
padding-right: 10px;
}
.status-column .el-tag {
margin: 2px 0;
}
由于summary-method会在每次数据更新时调用,复杂的JSX结构可能影响性能。可以通过缓存优化:
javascript复制computed: {
cachedSummaries() {
// 返回基础结构
return this.buildSummaryStructure()
}
},
methods: {
getSummaries() {
return this.cachedSummaries
}
}
在项目中我发现几个常见问题:
在移动端使用时需要注意:
css复制@media screen and (max-width: 768px) {
.summary-row {
font-size: 12px;
line-height: 20px;
}
}
这套方案已经在我们的生产环境稳定运行半年多,处理过各种边界情况。对于更复杂的需求,比如可交互的汇总行或动态列处理,还可以进一步扩展这个基础方案。