上万的数据如何在前端页面快速展示?

前端要呈现百万数据,这个需求是很少见的,但是展示千条稍微复杂点的数据,这种需求还是比较常见,只要内存够,javascript 肯定是吃得消的,计算几千上万条数据,js 效率根本不在话下,但是 DOM 的渲染浏览器扛不住,CPU 稍微搓点的电脑必然会卡爆。
首先,这种情况很少见。如果要在前端呈现大量的数据,一般的策略就是分页。虽然这么说,但是如果展示上百条数据,图片资源消耗,也会让页面发生卡顿。

JavaScript效率

DOM渲染卡顿

DOM渲染一直困扰前端的难题,由于设备参差不齐,CPU性能严重影响了页面的渲染能力。

方案

1
2
3
4
5
6
7
8
9
10
11
12
/==============> box
| .... | /
+--------------+/
+=======|=====List=====|========+
| +--------------+ |
| | List | |
| +--------------+ |\
| | List | | \
| +--------------+ | \======> Container
+=======|=====List=====|========+
+--------------+
| .... | Created By Barret Lee
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
function VirtualList(config) {
var vWidth = config.width ? (config && config.width + 'px') : '100%'
var vHeight = config.height ? (config && config.height + 'px') : '100%'
var itemHeight = this.itemHeight = config.itemH
// this.items = config.items
this.generatorFn = config.generatorFn
this.totalRows = config.totalRows || (config.items && config.items.length)
//List Num
var screenItemsLen = Math.ceil(config.height / itemHeight)
//cache List Num
this.cachedItemsLen = screenItemsLen * 3
console.log(config.height)
//Set Scroller init
var scroller = VirtualList.createScroller(itemHeight * this.totalRows)
this.container = VirtualList.createContainer(vWidth, vHeight)
this.container.appendChild(scroller)
this.render(this.container, 0)
var self = this
var lastRepaintY
var maxBuffer = screenItemsLen * itemHeight
var lastScrolled = 0
this.rmNodeInerval = setInterval(function() {
if (Date.now() - lastScrolled > 100) {
var badNodes = document.querySelectorAll('[data-virtual="1"]')
for (var i = 0, l = badNodes.length; i < l; i++) {
self.container.removeChild(badNodes[i])
}
}
}, 300)
function onScroll(e) {
var scrollTop = e.target.scrollTop
if (!lastRepaintY || Math.abs(scrollTop - lastRepaintY) > maxBuffer) {
var first = parseInt(scrollTop / itemHeight) - screenItemsLen
self.render(self.container, first < 0 ? 0 : first)
lastRepaintY = scrollTop
}
lastScrolled = Date.now()
e.preventDefault && e.preventDefault()
}
this.container.addEventListener('scroll', onScroll)
}
VirtualList.prototype.render = function(node, num) {
var allItem = num + this.cachedItemsLen
if (allItem > this.totalRows) {
allItem = this.totalRows
}
var fragment = document.createDocumentFragment()
// for add Item
console.log(allItem)
for (var i = num; i < allItem; i++) {
fragment.appendChild(this.createRow(i))
}
console.log(fragment)
for (var j = 1, l = node.childNodes.length; j < l; j++) {
node.childNodes[j].style.display = 'none'
node.childNodes[j].setAttribute('data-virtual', '1')
}
node.appendChild(fragment)
}
VirtualList.prototype.createRow = function(i) {
var item;
if (this.generatorFn) {
item = this.generatorFn(i)
} else if (this.items) {
}
item.classList.add('item')
item.style.position = 'absolute'
item.style.top = (i * this.itemHeight + 'px')
console.log(item)
return item
}
VirtualList.createContainer = function(width, height) {
var box = document.createElement('div')
box.style.width = width
box.style.height = height
box.style.overflow = 'auto'
box.style.position = 'relative'
box.style.padding = 0
box.style.border = '1px solid black'
return box
}
VirtualList.createScroller = function(boxH) {
var scroller = document.createElement('div')
scroller.style.opacity = 0
scroller.style.position = 'absolute'
scroller.style.top = 0
scroller.style.left = 0
scroller.style.width = '1px'
scroller.style.height = boxH + 'px'
return scroller
}
function dataInit (rows, cloumns) {
var data = []
for (var i = 0; i < cloumns; i++) {
var list = []
for (var j = 0; j < rows; j++) {
list.push({
content: 'item-' + (rows * i + j + 1),
id: rows * i + j + 1,
cloumns: i + 1,
rows: j + 1,
isNo: [true, false][Math.floor(Math.random()*[true, false].length)]
})
}
data.push({
id: i + 1,
list: list
})
}
return data
}

初始化

1
2
3
4
5
6
7
8
9
10
var List = new VirtualList({
width: 600, // box width
height: 300, // box height
itemH: 30, // item height
totalRows: data.length, // data
generatorFn: function(key) { // 生成器
var el = document.createElement('div')
return el
}
})

计算

容器何以显示的List个数

1
var screenItemsLen = Math.ceil(config.height / itemHeight)

缓存的List Div的数码

1
this.cachedItemsLen = screenItemsLen * 3

容器的整体高度

1
itemHeight * this.totalRows

render() 计算需要展示的内容,即将替换的内容
createRow() 创建List
createContainer() 创建容器
createScroller() 创建将容器撑起div

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. JavaScript效率
  2. 2. DOM渲染卡顿
    1. 2.1. 方案
      1. 2.1.1. 初始化
      2. 2.1.2. 计算
,