1、现象

有时候el-table的数据可能有成千上万条,而且又要在一页显示完,这时候页面渲染的dom太多了,可能会造成页面卡顿。

解决方案:给表格固定高度,只渲染用户在表格中滚动的视图dom

2、卡顿原因

因为数据量过多导致浏览器渲染过多的标签元素 导致DOM树占用内存较大 使得用户操作阻塞。
具体原理可参考别的大佬写的文章: DOM性能瓶颈与Javascript性能优化.

3、解决方法及原理

原理
解决思路可参考: 页面中长列表滚动的优化.

解决方法
使用第三方插件 https://www.npmjs.com/package/pl-table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
<template>
  <!-- 使用 useVirtual 属性开启虚拟滚动 使用虚拟滚动时,必须要固定表格高度和行高 -->
  <div style="height: 100%;width: 100%;padding: 0 30px">
    <div style="color:red;">pl-table在线预览,更多玩法请看文档哦,欢迎Star</div>
    <el-button @click="$router.push({ path: '/text' })"
      >去子页面(为了测试缓存组件)</el-button
    >
    <div>
      <el-button @click="allSelection">全选</el-button>
      <el-button @click="clearSelection">清除选中</el-button>
      <el-button @click="setData(3)">变化数据为3条</el-button>
      <el-button @click="setData(200)">变化数据为200条</el-button>
      <el-button @click="setData(1000)">变化数据为1000条</el-button>
      <el-button @click="pagingScrollTopLeft(1000)">滚动到1千位置</el-button>
      <el-button @click="pagingScrollTopLeft(2000)">滚动到2千位置</el-button>
      <el-button @click="pagingScrollTopLeft(0)">滚动到顶部</el-button>
      <el-button @click="scrollBottom">滚动到底部位置</el-button>
      <el-button @click="setHei(400)">设置高度为400</el-button>
      <el-button @click="setHei(300)">设置高度为300</el-button>
    </div>
 
    <!--我是Y轴虚拟-->
    <div v-if="true">
      <p style="color: red">我是Y轴虚拟</p>
      <pl-table
        ref="plTable"
        :height="height"
        :data="data.tableData"
        selectTrClass="selectTr"
        header-drag-style
        :dataChangesScrollTop="false"
        :summary-method="summaryMethod"
        @table-body-scroll="tableBodyScroll"
        fixedColumnsRoll
        inverse-current-row
        bigDataCheckbox
        @select-all="selectAll"
        show-summary
        use-virtual
        :row-height="rowHeight"
      >
        <template slot="empty">
          没有查询到符合条件的记录
        </template>
        <pl-table-column type="selection" width="55" :selectable="selectable" />
        <pl-table-column type="index" width="100" fixed />
        <!--show-overflow-tooltip属性代表超出则内容部分给出提示框-->
        <pl-table-column
          v-for="item in columns"
          :key="item.id"
          :resizable="item.resizable"
          :show-overflow-tooltip="item.showOverflowTooltip"
          :prop="item.prop"
          :label="item.label"
          :fixed="item.fixed"
          :width="item.width"
        />
      </pl-table>
    </div>
    <!--我是X + Y轴同时虚拟-->
    <div v-if="true">
      <p style="color: red">我是X + Y轴同时虚拟</p>
      <plx-table-grid
        :data="data.tableData"
        height="300"
        :show-summary="true"
        :summary-method="summaryMethod"
        ref="plTable2"
      >
        <plx-table-column type="selection" width="55" fixed="left" />
        <plx-table-column type="index" width="100" fixed="left" />
        <plx-table-column
          v-for="item in columns2"
          :key="item.id"
          :resizable="item.resizable"
          :prop="item.prop"
          :label="item.label"
          :fixed="item.fixed"
        />
      </plx-table-grid>
    </div>
 
    <!--我是加入分页的表格-->
    <div v-if="false">
      <p style="color: red">我是加入分页的表格</p>
      <pl-table
        :data="data.tableData"
        big-data-checkbox
        :max-height="height"
        header-drag-style
        fixedColumnsRoll
        use-virtual
        :row-height="rowHeight"
        :pagination-show="true"
        :total="pageForm.total"
        :page-size="pageForm.pageSize"
        :current-page="pageForm.currentPage"
        @handlePageSize="handlePageSize"
      >
        <template slot="empty">
          没有查询到符合条件的记录
        </template>
        <pl-table-column type="selection" width="55" />
        <pl-table-column type="index" width="100" fixed />
        <!--show-overflow-tooltip属性代表超出则内容部分给出提示框-->
        <pl-table-column
          v-for="item in columns"
          :key="item.id"
          :resizable="item.resizable"
          :show-overflow-tooltip="item.showOverflowTooltip"
          :prop="item.prop"
          :label="item.label"
          :fixed="item.fixed"
          :width="item.width"
        />
      </pl-table>
    </div>
 
    <!--我是普通的el-table树形表格,这个数据多了就卡,这就是原本的el-table树表格,必须指定 row-key-->
    <div v-if="false">
      <p style="color: red;">
        我是普通的el-table树形表格,这个数据多了就卡,这就是原本的el-table树表格,必须指定
        row-key
      </p>
      <pl-table
        ref="plTable"
        :height="height"
        :data="treeData"
        selectTrClass="selectTr"
        row-key="id"
        header-drag-style
        @table-body-scroll="tableBodyScroll"
        fixedColumnsRoll
        inverse-current-row
        @select-all="selectAll"
      >
        <template slot="empty">
          没有查询到符合条件的记录
        </template>
        <!--show-overflow-tooltip属性代表超出则内容部分给出提示框-->
        <pl-table-column
          v-for="item in columns"
          :key="item.id"
          :resizable="item.resizable"
          :show-overflow-tooltip="item.showOverflowTooltip"
          :prop="item.prop"
          :label="item.label"
          :fixed="item.fixed"
          :width="item.width"
        />
      </pl-table>
    </div>
 
    <!--我是pl-table大数据树形表格 必须指定 row-key  必须开启use-virtual-->
    <div v-if="true">
      <p style="color: red;">
        我是pl-table大数据树形表格 必须指定 row-key 必须开启use-virtual
      </p>
      <el-button @click="$refs.plTreeTable.toggleTreeExpansion(treeData[0])"
        >切换第一个</el-button
      >
      <el-button @click="$refs.plTreeTable.setTreeExpansion(treeData[2], true)"
        >展开第三个</el-button
      >
      <el-button @click="$refs.plTreeTable.setAllTreeExpansion()"
        >展开全部</el-button
      >
      <el-button @click="$refs.plTreeTable.clearTreeExpand()"
        >关闭所有</el-button
      >
      <el-button @click="getTreeExpansionEvent">获取已展开</el-button>
      <pl-table
        ref="plTreeTable"
        :max-height="height"
        :data="treeData"
        selectTrClass="selectTr"
        row-key="id"
        bigDataCheckbox
        :treeConfig="{ children: 'children', expandAll: false }"
        :use-virtual="true"
        header-drag-style
        @table-body-scroll="tableBodyScroll"
        fixedColumnsRoll
        inverse-current-row
        @select-all="selectAll"
      >
        <template slot="empty">
          没有查询到符合条件的记录
        </template>
        <!--pl-table大数据表格 你需要在列上指定某个列显示展开收起 treeNode属性-->
        <pl-table-column
          :treeNode="item.treeNode"
          v-for="item in columns"
          :key="item.id"
          :resizable="item.resizable"
          :show-overflow-tooltip="item.showOverflowTooltip"
          :prop="item.prop"
          :label="item.label"
          :fixed="item.fixed"
          :width="item.width"
        />
      </pl-table>
    </div>
  </div>
</template>
 
<script>
// 下面是关于pl-table的树形数据的介绍,希望读完下面的文字
 
// (最大数量500)当然你可以更多,那么只会导致你遍历时间多,页面等待时间长,(并非渲染节点时间长)
// 另外 就以下的这个层级,总数据量展开后,就是 500 + 500 x 3 + 3 x 1 = 2003 的总数据量
// 如果你 第一级是500, 第二级也是500, 第三级是10。 那么你的数据量就是 500 + 500 x 500 + 500 x 10 的总数据量,这是非常吓人的
// 所以结合自己情况去给树数据,不要瞎乱给下面的数据,树节点避免不鸟去递归,如果你的数据量很大很大,那么你会死在遍历上。
// 注意,注意,注意:并非第一级不能超过500,是想告诉你们嵌套里面子节点层级数据量不要太大。比如你可这样的: 第一级为1000, 第二级为2-5的数据量,
// 第三级为2-5的数据量...., 那么这样算下来,就是 1000 + 1000 x 5  + 5 x 5  = 6025的数据量,应该是可以的,但是记住要是太大的嵌套数据。那只会导致
// 程序卡在遍历数据上,因为程序需要慢慢去递归遍历。这是没有办法的。
 
// 但是传统el-table  或者el-tree他们数据量超过200  就会卡。 所以我们已经很好的优化了这一点。不过看来对于树形数据的要求,应该数据量不会太大。
// 你可以在pl-table的基础上去改改样式,就可以变相的去实现el-tree的组件了哦,你隐藏下头部,把行的高度给小一点。然后隐形边框线。是不是就是el-tree了呢???
 
var dataList = Array.from({ length: 500 }, (_, idx) => ({
  id: idx + "_" + 1,
  date: "2016-05-03",
  name: 1,
  ab: "欢迎使用pl-table",
  address: idx,
  children: Array.from({ length: 3 }, (_, idx2) => ({
    id: idx + "_" + idx2 + "_" + 1,
    date: "2016-05-03",
    name: 1,
    ab: "欢迎使用pl-table",
    address: idx + "_" + idx2,
    children: Array.from({ length: 1 }, (_, idx3) => ({
      id: idx + "_" + idx2 + "_" + idx3 + "_" + 1,
      date: "2016-05-03",
      name: 1,
      ab: "欢迎使用pl-table",
      address: idx + "_" + idx2 + "_" + idx3
    }))
  }))
}));
export default {
  name: "home",
  data() {
    return {
      rowHeight: 50,
      columns: [
        {
          prop: "address",
          label: "日期",
          width: 120,
          treeNode: true,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "地址",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "噜噜噜",
          width: 230,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "娃哈哈",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "地址",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "娃哈哈",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "娃哈哈",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "地址",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "娃哈哈",
          width: 100,
          showOverflowTooltip: true
        },
        {
          prop: "address",
          label: "娃哈哈",
          width: 100,
          showOverflowTooltip: true
        },
        { prop: "address", label: "噜噜噜", showOverflowTooltip: true },
        {
          prop: "address",
          label: "娃哈哈",
          width: 100,
          showOverflowTooltip: true,
          fixed: "right"
        }
      ],
      columns2: Array.from({ length: 20 }, (_, idx) => ({
        prop: "address",
        label: "地址" + idx,
        width: 200,
        showOverflow: true,
        sortable: true,
        fixed: ""
      })),
      data: {
        tableData: Array.from({ length: 10000 }, (_, idx) => ({
          id: idx + 1,
          date: "2016-05-03",
          name: 1,
          ab: "欢迎使用pl-table",
          address: 1 + idx
        }))
      },
      top: 0,
      height: 500,
      pageForm: {
        total: 1000,
        pageSize: 10,
        currentPage: 1
      },
      treeData: dataList
    };
  },
  methods: {
    selectAll(val) {
      console.log(val);
    },
    selectable(row, index) {
       
      if (index === 1) {
        return false;
      } else {
        console.log(row,index);
 
        return true;
      }
    },
    // 合计
    summaryMethod({ columns, data }) {
      // 平均值算法(不需要自己去掉)
      function cacl(arr, callback) {
        let ret;
        for (let i = 0; i < arr.length; i++) {
          ret = callback(arr[i], ret);
        }
        return ret;
      }
      // 平均值算法(不需要自己去掉)
      Array.prototype.sum = function() {
        return cacl(this, function(item, sum) {
          if (typeof sum == "undefined") {
            return item;
          } else {
            return (sum += item);
          }
        });
      };
      // 平均值算法(不需要自己去掉)
      Array.prototype.avg = function() {
        if (this.length == 0) {
          return 0;
        }
        return this.sum(this) / this.length;
      };
      const means = []; // 合计
      const fenceSums = []; // 平均值
      columns.forEach((column, columnIndex) => {
        if (columnIndex === 0) {
          means.push("合计");
          fenceSums.push("平均值");
        } else {
          const values = data.map(item => Number(item[column.property]));
          // 合计
          if (!values.every(value => isNaN(value))) {
            means[columnIndex] = values.reduce((prev, curr) => {
              const value = Number(curr);
              if (!isNaN(value)) {
                return prev + curr;
              } else {
                return prev;
              }
            }, 0);
            // means[columnIndex] += ' 元'
            // 改变了ele的合计方式,扩展了合计场景
            // 你以为就只有上面这样玩吗?错啦,你还可以自定义样式哦
            // means[columnIndex] = '<span style="color: red">' + means[columnIndex] + '元</span>'
            means[columnIndex] =
              '<span style="color: red">' +
              means[columnIndex] +
              "元</span><br/><span>123</span>";
          } else {
            means[columnIndex] = "";
          }
          // 平均值
          const precisions = [];
          let notNumber = true;
          values.forEach(value => {
            if (!isNaN(value)) {
              notNumber = false;
              let decimal = ("" + value).split(".")[1];
              precisions.push(decimal ? decimal.length : 0);
            }
          });
          if (!notNumber) {
            fenceSums[columnIndex] = values.avg();
          } else {
            fenceSums[columnIndex] = "";
          }
        }
      });
      // 返回一个二维数组的表尾合计
      return [means, fenceSums];
    },
    setHei(val) {
      this.height = val;
    },
    tableBodyScroll({ scrollTop }) {
      this.top = scrollTop;
    },
    allSelection() {
      this.$refs.plTable.toggleAllSelection();
    },
    clearSelection() {
      this.$refs.plTable.clearSelection();
      this.$refs.plTable2.clearSelection();
    },
    setData(num) {
      this.data.tableData = Array.from({ length: num }, (_, idx) => ({
        id: idx + 1,
        date: "2016-05-03",
        name: 1,
        ab: "欢迎使用pl-table",
        address: 1 + idx
      }));
    },
    scrollBottom() {
      this.$refs.plTable.scrollBottom();
    },
    pagingScrollTopLeft(val) {
      this.$refs.plTable.pagingScrollTopLeft(val, 0);
    },
    // 分页事件
    handlePageSize({ page, size }) {
      console.log(page, size);
    },
    // 获取已经展开的节点
    getTreeExpansionEvent() {
      console.log(this.$refs.plTreeTable.getTreeExpandRecords());
    }
  }
};
</script>
<style>
body,
html {
  margin: 0;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
}
body ::-webkit-scrollbar-thumb {
  -webkit-border-radius: 5px;
  border-radius: 5px;
  background-color: rgba(144, 147, 153, 0.5);
}
.selectTr td {
  background: #ccc !important;
  color: red !important;
}
</style>

 demo: https://livelypeng.github.io/pl-table/website-project/dist/index.html 

推荐使用umy-ui

posted on   ygunoil  阅读(8023)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2021-03-04 esbuild
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示