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秒多的时间,可想而知如果一次性渲染几百行几千行,消耗的时间肯定会大大影响用户体验。当然,这种页面性能的优化不仅仅分批渲染一种手段,后面我会持续探索,如果有了新的手段,也会总结成文的。

感谢阅读!

相关推荐
不一样的少年_18 分钟前
同事以为要重写,我8行代码让 Vue 2 公共组件跑进 Vue 3
前端·javascript·vue.js
Zz_waiting.2 小时前
案例开发 - 日程管理 - 第六期
前端·javascript·vue.js·路由·router
A 风2 小时前
封装日期选择器组件,带有上周,下周按钮
开发语言·javascript·vue.js
Simon_He2 小时前
vue-markdown-renderer:比 vercel streamdown 更低 CPU、更多节点支持、真正的流式渲染体验
前端·vue.js·markdown
BillKu3 小时前
npm 安装命令中关于 @ 的讲解,如:npm install @vue-office/docx vue-demi
前端·vue.js·npm
超人不会飛4 小时前
大模型应用 Vue H5 模板:快速落地流式交互与富文本渲染的开箱方案
前端·vue.js·github
奇怪的前端74 小时前
Alien-Signals 响应式系统
前端·vue.js
DLF_ou4 小时前
vue3+openlayers项目初始化
vue.js
华仔啊4 小时前
Vue 的 DOM 更新竟然是异步的?90%的人没有搞懂 nextTick
前端·vue.js
Ankle5 小时前
vue3 父子组件v-model传值方法总结
前端·vue.js