• 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; 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

  • 相关阅读:
    VMware Workstation网卡不启动
    解决IE10以下对象不支持“bind”属性或方法
    二分法查找
    选择排序与冒泡排序
    方法内部开启线程的方法
    重写Collections实现自定义排序
    根据反射生成SQL语句
    vue插件安装备忘
    vue cli4.x 新建项目 过程提醒
    php setcooike()失败的原因之一,希望能帮到你
  • 原文地址:https://www.cnblogs.com/liangtao999/p/13162171.html
Copyright © 2020-2023  润新知