Vue中 el-table大數據量加載,不分頁,節省內存的性能優化


問題描述:

數據使用el-table加載,大概有1萬多條。頁面非常卡,查看內存占用到1.1個G,存在嚴重的性能問題。

 

考慮思路:

1、用table或者pl-table替換el-table。嘗試后發現性能提升不大,仍然占用大量內存。

2、網上很多解決方案是說通過分頁來加載,但我們的列表數據有關聯,不能使用分頁。

 

原因及解決方案:

經查,性能差的主要原因是,列表生成過程中產生大量的虛擬dom和真實dom,大量占用內存。

解決思路。
1、假滾動事件:拖動滾動滑塊,並不會影響左側的真實滾動,只是記錄滾動的位置。
2、根據滾動的位置,計算出對應的數據區間段,比如應該取340-350這10條。
3、根據滾動位置,和數據區間,把這幾條數據控制絕對定位,來模擬滾動效果。

參考的完整代碼:

<template>
    <div class="list" style="height: 300px;overflow: scroll" ref="scrollDom" @scroll="scroll">
        <div :style="{height:list.length*40+'px'}"></div>
        <div style="position:absolute;width: 100%" :style="{top:startIndex*40+'px'}">
            <div v-for="(item,index) in splitData" :key="index" class="item">
                <div v-html="item.id"></div>
                <div v-html="item.name"></div>
                <div v-html="item.createTime"></div>
                <div>
                    <Button>修改</Button>
                    <Button>刪除</Button>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        created() {
            for (let i = 0; i < 10000; i++) {
                this.list.push({
                    id: 1,
                    name: 'name' + i,
                    createTime: '2018-09-09'
                })
            }
        },
        computed: {
            limitCount() {
                return 300 / 40 + 2;
            },
            splitData() {
                return this.list.slice(this.startIndex, this.startIndex + this.limitCount)
            }
        },
        data() {
            return {
                startIndex: 0,
                list: []
            }
        },
        methods: {
            scroll() {
                // 根據滾動的距離,估算出這個滾動位置對應的數組序列,例如滾動100px,每條40px,對應第3條
                let scrollTop = this.$refs.scrollDom.scrollTop;
                this.startIndex = Math.floor(scrollTop / 40);
            }
        }
    }
</script>
<style scoped lang="less">
    .list {
        border: solid 1px #5f5f5f;
        background-color: white;
        margin: 100px 0;
        padding: 5px;
        width: 500px;
        position: relative;

        .item {
            display: flex;
            height: 40px;

            > * {
                flex-grow: 1;
                border: solid 1px #9e9e9e;
                padding: 3px;
            }
        }
    }
</style>

無論怎么滾動,效果跟全部加載是一樣的,但是通過右側的控制台發現,dom數量只有固定的這幾個,但是每個dom內部的值在不停的修改。

我們實際應用后的例子:

<template>
    <div class="qingDan" v-show="typeCur==1" v-loading="loading1">
        <div class="glptLeft2">
            <p @click="ChangceTableCur(1)" :class="{active:tableCur==1}">清單匯總表</p>
            <p @click="ChangceTableCur(2)" :class="{active:tableCur==2}">樓層明細表</p>
            <p @click="ChangceTableCur(3)" :class="{active:tableCur==3}">清單構件明細表</p>
            <p @click="ChangceTableCur(4)" :class="{active:tableCur==4}">清單構件計算書</p>
            <p @click="ChangceTableCur(5)" :class="{active:tableCur==5}">清單樓層計算書</p>
            <el-button class="daochu-btn" type="primary" @click="DowloadTable()">導出</el-button>
        </div>
        <div class="qingDanRight" style="height:100%;overflow: auto;position:relative" ref="scrollDom" @scroll="scroll">
            <div :style="{height:tableData.length*40+'px'}"></div>
            <table style="position:absolute" :style="{top:(startIndex*40)+'px'}">
                <tr class="tabletitle">
                    <td width="80">序號</td>
                    <td width="100" v-if="tableCur==5">樓層</td>
                    <td width="200">編碼</td>
                    <td width="300">項目名稱</td>
                    <td width="260">項目特征</td>
                    <td width="100" v-if="tableCur==2">樓層</td>
                    <td width="80">單位</td>
                    <td width="100">工程量</td>
                    <td width="100" v-if="tableCur==1">圖形工程量</td>
                    <td width="300" v-if="tableCur==4||tableCur==5">計算式</td>
                    <td width="200" v-if="tableCur==1||tableCur==4||tableCur==5">增加</td>
                    <td width="200"v-if="tableCur==1||tableCur==4||tableCur==5">扣減</td>
                </tr>
                <tr v-for="(item,index) in splitData" :key='index' >
                    <td class="center" width="80">{{item.XuHao}}</td>
                    <td class="center" width="100"v-if="tableCur==5">{{item.LouCeng}}</td>
                    <td width="200">{{item.FeiYongCode}}</td>
                    <td width="300">{{item.MC}}</td>
                    <td width="260">{{item.TZ}}</td>
                    <td width="100" v-if="tableCur==2">{{item.LouCeng}}</td>
                    <td class="center" width="80">{{item.DW}}</td>
                    <td class="center" width="100">{{item.GCL}}</td>
                    <td width="100" v-if="tableCur==1">{{item.TuXingGCL}}</td>
                    <td width="300" v-if="tableCur==4||tableCur==5">{{item.JSGS}}</td>
                    <td width="200" v-if="tableCur==1||tableCur==4||tableCur==5">{{item.Add}}</td>
                    <td width="200" v-if="tableCur==1||tableCur==4||tableCur==5">{{item.Reduce}}</td>
                    
                </tr>

            </table>
        </div>
    </div>
</template>

<script>
    import axios from "axios";
    import {
        AxiosPostApi
    } from "../../../api/common/common.js";
    export default {
        name: "TableCommon",
        data() {
            return {
                tableData: [],
                startIndex:0,
                loading1: false,
                tableCur: 1, //工程量匯總選中表
            }
        },
        props: {
            typeCur: Number,
            checkGuid: String
        },
        created() {
            this.GetTableData(1);
        },
        computed: {
            limitCount() {
                let height= document.body.scrollHeight;
                return height / 40 + 2;
            },
            splitData() {
                return this.tableData.slice(this.startIndex, this.startIndex + this.limitCount)
            }
        },
        methods: {
            //導出清單表
            DowloadTable() {
                let data = {
                    Method: 'SLHuiZongExport',
                    DW_EngineerID: this.checkGuid
                }
                AxiosPostApi('', data).then(response => {
                    window.open(process.env.API_ROOT_FILE + response.data.filePath, "_blank");
                });
            },
            //切換工程量表
            ChangceTableCur(e) {
                this.tableCur = e;
                this.GetTableData()
            },
            //獲取工程量表
            GetTableData(e) {
                this.loading1 = true;
                let data = {
                    Method: 'SLHuiZong',
                    DW_EngineerID: this.checkGuid,
                    oType: this.tableCur
                }
                AxiosPostApi('', data).then(response => {
                    this.tableData = response.data.LstHZView
                    this.loading1 = false;
                });
            },
            scroll() {
                // 根據滾動的距離,估算出這個滾動位置對應的數組序列,例如滾動100px,每條40px,對應第3條
                let scrollTop = this.$refs.scrollDom.scrollTop;
                this.startIndex = Math.floor(scrollTop / 40);
            }

        },
        watch: {
          checkGuid(){
              this.GetTableData(1);
              this.tableCur = 1;
          }
        },
    }
</script>

<style scoped>
    @import "../../../assets/css/chengGuoJiaoFuDetail.css";

    .el-breadcrumb__inner.is-link,
    .el-breadcrumb__inner span {
        color: #257ed8;
        font-weight: 700;
        cursor: pointer;
    }

    /* 圓環 */
    .circle /deep/ .el-progress-circle {
        width: 50px !important;
        height: 50px !important;
    }

    .circle /deep/ .el-progress__text {
        color: #599adb;
        font-size: 15px !important;
    }
</style>
<style>
    /* 切換單位工程 */
    .el-tree-node__content {
        height: 40px;
        padding-left: 20px !important;
    }

    .el-tree-node__children .el-tree-node__content {
        height: 40px;
        padding-left: 40px !important;
    }

    .el-breadcrumb__inner.is-link {
        color: #257ed8;
    }

    .el-drawer__body {
        padding: 20px 0px;
    }
    .tabletitle td,.center{
        text-align: center;
    }
    table td{
        height: 40px;
    }
</style>

效果及內存:

參考文檔:https://www.cnblogs.com/wanghaoran5555/articles/11177990.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM