vue3项目中实现el-table分批渲染表格

开篇

因最近工作中遇到了无分页情景下页面因大数据量卡顿的问题,在分别考虑并尝试了懒加载、虚拟滚动、分批渲染等各个方法后,最后决定使用分批渲染来解决该问题。

代码实现

表格代码

javascript 复制代码
<el-table 
    :data="currTableData"
    border
    style="width: 100%;"
    :max-height="getMaxHeight()"
    :cell-style="CellStyle" 
    @cell-click="handleCellClick"
>
    <!--姓名列-->
    <el-table-column 
        style="background-color: #fff;"
        :align="'center'"
        prop="userName"
        label="姓名"
        width="80"
        fixed/>
    <!--工号-->
    <el-table-column 
        v-for="(item, index) in filteredCfgColumns"
        :key="index"
        style="background-color: #fff;"
        :align="'center'"
        :prop="item.prop"
        :label="item.label"
    />

    <!--
        这一块牵扯到合并列及周期模式切换后的动态展示
        需要特殊处理,不要写死
    -->
    <el-table-column 
        v-for="(date, index) in dateHeaders" 
        :key="index" 
        :align="'center'"
        :class-name="isWeekend(date)"
        :label-class-name="isWeekend(date)"
        :width="getColumnWidth()"
    >
        <!--星期几/日期-->
        <template #header>
            <div>{{ getWeekDay(date) }}</div>
            <div>{{ parseDate(date) }}</div>
        </template>

        <!--表格内容 -->
        <template #default="{row}">
            <div 
                class="cell-content"
                v-if="row[date]"
                :data-cell-content="JSON.stringify(row[date])"
                :class="`${row[date].cellKey}`"
            >
                <!-- 第一行 -->
                <div v-if="pageSettingList.includes('显示附加班')" class="row"
                    style="font-size: 8px;min-height: 12px; display: flex; align-items: center;">
                    <el-row style="width: 100%;">
                        <el-col :span="24" style="color: red;font-weight: 600;text-align: right;">
                            {{ row[date]?.attchDetail || '' }}
                        </el-col>
                    </el-row>
                </div>
                <!-- 第二行 -->
                <div class="row"
                    style="font-size: 10px;min-height: 20px; display: flex; align-items: center;white-space: nowrap;overflow: hidden;">
                    <el-row style="width: 100%;">
                        <el-col :span="24" style="font-weight: 600;text-align: center;">
                            <StyledText :colorAndSchedules="colorAndSchedules"
                                :styledTexts="row[date]?.mainDetail || ''" />
                        </el-col>
                    </el-row>
                </div>
                <!-- 第三行 -->
                <div class="row"
                    style="font-size: 8px;min-height: 12px; display: flex; align-items: center;">
                    <el-row style="width: 100%;">
                        <el-col :span="6" v-if="pageSettingList.includes('显示上期排班')"
                            style="display: block;text-align: left;font-weight: 600;color: green;">
                            {{ 'A1' }}
                        </el-col>
                        <el-col :span="12" v-if="pageSettingList.includes('显示申请班')"
                            style="display: block;text-align: center;font-weight: 600;color: green;">
                            {{ row[date]?.applyDetail || '' }}
                        </el-col>
                        <el-col :span="6" 
                            style="display: block;text-align: left;font-weight: 600;color: green;">  
                            <div class="tip-con">
                                <el-tooltip
                                style="position: absolute!important; right: 0;bottom: 0; color: red; font-size: 12px;" 
                                placement="top" 
                                v-if="isShowRemark(row[date]?.remarkInfo)">
                                    <template #content>
                                        <el-table :data="row[date]?.remarkInfo" style="width: 100%">
                                            <el-table-column prop="shifts" label="班次名" width="180" />
                                            <el-table-column prop="remark" label="备注" width="180" />
                                            <el-table-column prop="type" label="班次类型" />
                                        </el-table>
                                    </template>
                                    <el-icon><InfoFilled /></el-icon>
                                </el-tooltip>
                            </div>
                        </el-col>
                    </el-row>
                </div>                                 
            </div>
        </template>
    </el-table-column>
</el-table>

分批渲染逻辑代码

  • 定义变量

    startIndex: 0, //开始索引,用于分批渲染的
    batchSize: 6, // 一次性渲染的条数

  • 分批渲染方法

    const currTableData = ref([])

    const loadBatch = () => {
    if (state.startIndex < props.tableData.length) {
    const endIndex = Math.min(state.startIndex + state.batchSize, props.tableData.length);
    currTableData.value = currTableData.value.concat(props.tableData.slice(state.startIndex, endIndex));
    state.startIndex = endIndex;
    requestAnimationFrame(loadBatch);
    }
    }

    watch(() => props.tableData, newData => {
    currTableData.value = []; // 重置数据
    state.startIndex = 0;
    loadBatch()
    }, { immediate: true })

效果

上面便是分批渲染表格的具体实现方式,可以看到这个表格是相当复杂的,哪怕是使用了分批渲染,第一次也用了6秒多的时间,可想而知如果一次性渲染几百行几千行,消耗的时间肯定会大大影响用户体验。当然,这种页面性能的优化不仅仅分批渲染一种手段,后面我会持续探索,如果有了新的手段,也会总结成文的。

感谢阅读!

相关推荐
踩着两条虫17 小时前
VTJ.PRO AI Agent 技术白皮书
前端·vue.js·低代码
java1234_小锋20 小时前
Vue3专题 - 列表渲染
vue.js
小锋java12341 天前
【技术专题】Vue3 - 列表渲染
vue.js·vite
zho_uzhou1 天前
ubuntu服务端运行vue网页步骤
linux·服务器·vue.js·ubuntu
滴滴答答哒1 天前
VUE3+element-plus MultiSelect 多选下拉组件
前端·javascript·vue.js
其美杰布-富贵-李1 天前
04 watch 与 Vue 响应式数据流
前端·javascript·vue.js
其美杰布-富贵-李2 天前
03 ref、reactive 与 computed 响应式数据
前端·javascript·vue.js
嘟嘟07172 天前
useRef + Web Worker:React 中的耗时计算不卡页面
javascript·vue.js
万敏2 天前
Vue3 全栈实战第五周:Vitest 单元测试从零搭建实战记录
vue.js·node.js·全栈
sugar__salt2 天前
跟着 Demo 学 Pinia:两种仓库写法 + 完整 TodoList 复现
前端·javascript·vue.js·前端框架·vue