@@ -3,9 +3,7 @@ import $ from 'licia/$'
3
3
import throttle from 'licia/throttle'
4
4
import isHidden from 'licia/isHidden'
5
5
import now from 'licia/now'
6
- import ResizeSensor from 'licia/ResizeSensor'
7
6
import isEmpty from 'licia/isEmpty'
8
- import map from 'licia/map'
9
7
import each from 'licia/each'
10
8
import clone from 'licia/clone'
11
9
import some from 'licia/some'
@@ -69,35 +67,45 @@ export default class VirtualList extends Component<IOptions> {
69
67
/** Clear all items. */
70
68
clear ( ) {
71
69
this . items = [ ]
72
- this . el . textContent = ''
70
+ this . render ( )
73
71
}
74
72
/** Append item. */
75
73
append ( el : HTMLElement ) {
76
- const item = new Item ( el , this . el )
74
+ const item : Item = ( el as any ) . virtualListItem || new Item ( el )
77
75
this . items . push ( item )
78
- this . updateSize ( item )
76
+ this . update ( el )
79
77
}
80
78
/** Set items. */
81
79
setItems ( els : HTMLElement [ ] ) {
82
- each ( this . items , ( item ) => item . destroy ( ) )
83
- this . items = map ( els , ( el ) => new Item ( el , this . el ) )
84
80
this . updateItems = [ ]
81
+ each ( els , el => this . append ( el ) )
85
82
}
86
- /** Recalculate all heights. */
87
- update ( ) {
88
- this . updateSize ( )
83
+ /** Remove item. */
84
+ remove ( el : HTMLElement ) {
85
+ const item = ( el as any ) . virtualListItem
86
+ if ( ! item ) {
87
+ return
88
+ }
89
+ const idx = this . items . indexOf ( item )
90
+ if ( idx === - 1 ) {
91
+ return
92
+ }
93
+ this . items . splice ( idx , 1 )
94
+ item . destroy ( )
95
+ this . render ( )
89
96
}
90
- private updateSize ( item ?: Item ) {
91
- if ( item ) {
92
- this . updateItems . push ( item )
97
+ /** Update heights. */
98
+ update ( el ?: HTMLElement ) {
99
+ if ( el ) {
100
+ this . updateItems . push ( ( el as any ) . virtualListItem )
93
101
} else {
94
102
this . updateItems = clone ( this . items )
95
103
}
96
104
if ( ! this . updateTimer ) {
97
- this . _updateSize ( )
105
+ this . _update ( )
98
106
}
99
107
}
100
- private _updateSize = ( ) => {
108
+ private _update = ( ) => {
101
109
const items = this . updateItems . splice ( 0 , 1000 )
102
110
if ( isEmpty ( items ) ) {
103
111
return
@@ -111,14 +119,14 @@ export default class VirtualList extends Component<IOptions> {
111
119
}
112
120
fakeEl . appendChild ( fakeFrag )
113
121
for ( let i = 0 ; i < len ; i ++ ) {
114
- items [ i ] . updateSize ( )
122
+ items [ i ] . update ( )
115
123
}
116
124
fakeEl . textContent = ''
117
125
118
126
this . render ( )
119
127
120
128
if ( ! isEmpty ( this . updateItems ) ) {
121
- this . updateTimer = setTimeout ( ( ) => this . _updateSize ( ) , 100 )
129
+ this . updateTimer = setTimeout ( ( ) => this . _update ( ) , 16 )
122
130
} else {
123
131
this . updateTimer = null
124
132
}
@@ -165,7 +173,7 @@ export default class VirtualList extends Component<IOptions> {
165
173
let topSpaceHeight = 0
166
174
let bottomSpaceHeight = 0
167
175
let currentHeight = 0
168
- let currentWidth = this . spaceWidth
176
+ let currentWidth = 0
169
177
170
178
const len = items . length
171
179
@@ -193,7 +201,10 @@ export default class VirtualList extends Component<IOptions> {
193
201
this . updateTopSpace ( topSpaceHeight )
194
202
this . updateBottomSpace ( bottomSpaceHeight )
195
203
196
- if ( ! some ( displayItems , ( item , idx ) => item !== this . displayItems [ idx ] ) ) {
204
+ if (
205
+ len > 0 &&
206
+ ! some ( displayItems , ( item , idx ) => item !== this . displayItems [ idx ] )
207
+ ) {
197
208
return
198
209
}
199
210
@@ -209,22 +220,23 @@ export default class VirtualList extends Component<IOptions> {
209
220
const { scrollHeight } = container
210
221
if ( this . isAtBottom && scrollTop <= scrollHeight - offsetHeight ) {
211
222
container . scrollTop = 10000000
223
+ this . render ( )
212
224
}
213
225
}
214
226
} ,
215
227
16
216
228
)
217
229
private onScroll = ( ) => {
218
- const { scrollHeight, offsetHeight , scrollTop } = this
230
+ const { scrollHeight, clientHeight , scrollTop } = this
219
231
. container as HTMLElement
220
232
// safari bounce effect
221
233
if ( scrollTop <= 0 ) return
222
- if ( offsetHeight + scrollTop > scrollHeight ) return
234
+ if ( clientHeight + scrollTop > scrollHeight ) return
223
235
224
236
let isAtBottom = false
225
- if ( scrollHeight === offsetHeight ) {
237
+ if ( scrollHeight === clientHeight ) {
226
238
isAtBottom = true
227
- } else if ( Math . abs ( scrollHeight - offsetHeight - scrollTop ) < 1 ) {
239
+ } else if ( Math . abs ( scrollHeight - clientHeight - scrollTop ) < 1 ) {
228
240
isAtBottom = true
229
241
}
230
242
this . isAtBottom = isAtBottom
@@ -262,7 +274,7 @@ export default class VirtualList extends Component<IOptions> {
262
274
if (
263
275
this . topSpaceHeight < scrollTop - topTolerance &&
264
276
this . topSpaceHeight + this . el . offsetHeight >
265
- scrollTop + offsetHeight + bottomTolerance
277
+ scrollTop + clientHeight + bottomTolerance
266
278
) {
267
279
return
268
280
}
@@ -285,26 +297,16 @@ class Item {
285
297
el : HTMLElement
286
298
width : number
287
299
height : number
288
- private resizeSensor : ResizeSensor
289
- constructor ( el : HTMLElement , container : HTMLElement ) {
300
+ constructor ( el : HTMLElement ) {
290
301
this . el = el
302
+ ; ( el as any ) . virtualListItem = this
291
303
this . width = 0
292
304
this . height = 0
293
-
294
- this . resizeSensor = new ResizeSensor ( el )
295
- this . resizeSensor . addListener ( ( ) => {
296
- if ( el . parentNode === container ) {
297
- this . updateSize ( )
298
- }
299
- } )
300
305
}
301
306
destroy ( ) {
302
- this . resizeSensor . destroy ( )
307
+ delete ( this . el as any ) . virtualListItem
303
308
}
304
- updateSize ( ) {
305
- if ( isHidden ( this . el ) ) {
306
- return
307
- }
309
+ update ( ) {
308
310
const { width, height } = this . el . getBoundingClientRect ( )
309
311
this . width = width
310
312
this . height = height
0 commit comments