Skip to content

Commit 3e7728c

Browse files
committed
Build
1 parent 61b7689 commit 3e7728c

File tree

1 file changed

+106
-81
lines changed

1 file changed

+106
-81
lines changed

dist/index.js

Lines changed: 106 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@
4343
BEHIND: 'BEHIND' // scroll down or right.
4444

4545
};
46-
var SIZE_TYPE = {
46+
var CALC_TYPE = {
4747
INIT: 'INIT',
4848
FIXED: 'FIXED',
4949
DYNAMIC: 'DYNAMIC'
5050
};
51+
var LEADING_BUFFER = 1;
5152

5253
var Virtual = /*#__PURE__*/function () {
5354
function Virtual(param, updateHook) {
@@ -64,12 +65,11 @@
6465
this.updateHook = updateHook; // size data.
6566

6667
this.sizes = new Map();
67-
this.caches = new Map();
6868
this.firstRangeTotalSize = 0;
6969
this.firstRangeAverageSize = 0;
70-
this.lastCalculatedIndex = 0;
71-
this.sizeType = SIZE_TYPE.INIT;
72-
this.sizeTypeValue = 0; // scroll data.
70+
this.lastCalcIndex = 0;
71+
this.fixedSizeValue = 0;
72+
this.calcType = CALC_TYPE.INIT; // scroll data.
7373

7474
this.offset = 0;
7575
this.direction = ''; // range data.
@@ -79,11 +79,9 @@
7979
if (this.param && !this.param.disabled) {
8080
this.checkRange(0, param.keeps - 1);
8181
} // benchmark test data.
82+
// this.__bsearchCalls = 0
83+
// this.__getIndexOffsetCalls = 0
8284

83-
84-
this.__bsearchCalls = 0;
85-
this.__getIndexOffsetCalls = 0;
86-
this.__getIndexOffsetCacheHits = 0;
8785
}
8886
}, {
8987
key: "destroy",
@@ -100,6 +98,16 @@
10098
range.padFront = this.range.padFront;
10199
range.padBehind = this.range.padBehind;
102100
return range;
101+
}
102+
}, {
103+
key: "isLower",
104+
value: function isLower() {
105+
return this.direction === DIRECTION_TYPE.BEHIND;
106+
}
107+
}, {
108+
key: "isUpper",
109+
value: function isUpper() {
110+
return this.direction === DIRECTION_TYPE.FRONT;
103111
} // return start index offset.
104112

105113
}, {
@@ -122,13 +130,13 @@
122130
// if there is no size value different from this at next comming saving
123131
// we think it's a fixed size list, otherwise is dynamic size list.
124132

125-
if (this.sizeType === SIZE_TYPE.INIT) {
126-
this.sizeTypeValue = size;
127-
this.sizeType = SIZE_TYPE.FIXED;
128-
} else if (this.sizeType === SIZE_TYPE.FIXED && this.sizeTypeValue !== size) {
129-
this.sizeType = SIZE_TYPE.DYNAMIC; // it's no use at all.
133+
if (this.calcType === CALC_TYPE.INIT) {
134+
this.fixedSizeValue = size;
135+
this.calcType = CALC_TYPE.FIXED;
136+
} else if (this.calcType === CALC_TYPE.FIXED && this.fixedSizeValue !== size) {
137+
this.calcType = CALC_TYPE.DYNAMIC; // it's no use at all.
130138

131-
delete this.sizeTypeValue;
139+
delete this.fixedSizeValue;
132140
} // calculate the average size only in the first range.
133141

134142

@@ -139,19 +147,28 @@
139147
// it's done using.
140148
delete this.firstRangeTotalSize;
141149
}
142-
} // when dataSources length change, we need to force update
143-
// just keep the same range and recalculate pad front and behind.
150+
} // in some special situation (e.g. length change) we need to update in a row
151+
// try goiong to render next range by a leading buffer according to current direction.
144152

145153
}, {
146-
key: "handleDataSourcesLengthChange",
147-
value: function handleDataSourcesLengthChange() {
148-
this.updateRange(this.range.start, this.range.end);
154+
key: "handleDataSourcesChange",
155+
value: function handleDataSourcesChange() {
156+
var start = this.range.start;
157+
158+
if (this.direction === DIRECTION_TYPE.FRONT) {
159+
start = start - LEADING_BUFFER;
160+
} else if (this.direction === DIRECTION_TYPE.BEHIND) {
161+
start = start + LEADING_BUFFER;
162+
}
163+
164+
start = Math.max(start, 0);
165+
this.updateRange(start, this.getEndByStart(start));
149166
} // when slot size change, we also need force update.
150167

151168
}, {
152169
key: "handleSlotSizeChange",
153170
value: function handleSlotSizeChange() {
154-
this.handleDataSourcesLengthChange();
171+
this.handleDataSourcesChange();
155172
} // calculating range on scroll.
156173

157174
}, {
@@ -171,19 +188,14 @@
171188
}
172189
} // ----------- public method end. -----------
173190

174-
}, {
175-
key: "isFixedSize",
176-
value: function isFixedSize() {
177-
return this.sizeType === SIZE_TYPE.FIXED;
178-
}
179191
}, {
180192
key: "handleFront",
181193
value: function handleFront() {
182194
var overs = this.getScrollOvers(); // should not change range if start doesn't exceed overs.
183195

184196
if (overs > this.range.start) {
185197
return;
186-
} // move up start by a buffer length.
198+
} // move up start by a buffer length, and make sure its safety.
187199

188200

189201
var start = Math.max(overs - this.param.buffer, 0);
@@ -212,8 +224,8 @@
212224
} // if this list is fixed size, that can be easily.
213225

214226

215-
if (this.isFixedSize()) {
216-
return Math.floor(offset / this.sizeTypeValue);
227+
if (this.isFixedType()) {
228+
return Math.floor(offset / this.fixedSizeValue);
217229
}
218230

219231
var low = 0;
@@ -222,9 +234,9 @@
222234
var high = this.param.uniqueIds.length;
223235

224236
while (low <= high) {
237+
// this.__bsearchCalls++
225238
middle = low + Math.floor((high - low) / 2);
226239
middleOffset = this.getIndexOffset(middle);
227-
this.__bsearchCalls++;
228240

229241
if (middleOffset === offset) {
230242
return middle;
@@ -236,41 +248,35 @@
236248
}
237249

238250
return low > 0 ? --low : 0;
239-
} // return a scroll offset from given index.
240-
// @todo can efficiency be improved more here?
251+
} // return a scroll offset from given index, can efficiency be improved more here?
252+
// although the call frequency is very high, its only a superposition of numbers.
241253

242254
}, {
243255
key: "getIndexOffset",
244256
value: function getIndexOffset(givenIndex) {
245-
// we know this without calculate!
257+
// we know this.
246258
if (!givenIndex) {
247259
return 0;
248-
} // get from cache if possible.
249-
250-
251-
if (this.caches.has(givenIndex)) {
252-
this.__getIndexOffsetCacheHits++;
253-
return this.caches.get(givenIndex);
254260
}
255261

256262
var offset = 0;
257263
var indexSize = 0;
258264

259265
for (var index = 0; index <= givenIndex; index++) {
260-
this.__getIndexOffsetCalls++; // cache last index offset if exist.
261-
262-
if (index && indexSize) {
263-
this.caches.set(index, offset);
264-
}
265-
266+
// this.__getIndexOffsetCalls++
266267
indexSize = this.sizes.get(this.param.uniqueIds[index]);
267268
offset = offset + (indexSize || this.getEstimateSize());
268269
} // remember last calculate index.
269270

270271

271-
this.lastCalculatedIndex = Math.max(this.lastCalculatedIndex, givenIndex - 1);
272-
this.lastCalculatedIndex = Math.min(this.lastCalculatedIndex, this.getLastIndex());
272+
this.lastCalcIndex = Math.max(this.lastCalcIndex, givenIndex - 1);
273+
this.lastCalcIndex = Math.min(this.lastCalcIndex, this.getLastIndex());
273274
return offset;
275+
}
276+
}, {
277+
key: "isFixedType",
278+
value: function isFixedType() {
279+
return this.calcType === CALC_TYPE.FIXED;
274280
} // return the real last index.
275281

276282
}, {
@@ -323,8 +329,8 @@
323329
}, {
324330
key: "getPadFront",
325331
value: function getPadFront() {
326-
if (this.isFixedSize()) {
327-
return this.sizeTypeValue * this.range.start;
332+
if (this.isFixedType()) {
333+
return this.fixedSizeValue * this.range.start;
328334
} else {
329335
return this.getIndexOffset(this.range.start);
330336
}
@@ -337,18 +343,18 @@
337343
var end = this.range.end;
338344
var lastIndex = this.getLastIndex();
339345

340-
if (this.isFixedSize()) {
341-
return (lastIndex - end) * this.sizeTypeValue;
342-
} // if already calculate all, return the exactly padding.
346+
if (this.isFixedType()) {
347+
return (lastIndex - end) * this.fixedSizeValue;
348+
} // if calculated all already, return the exactly offset.
343349

344350

345-
if (this.lastCalculatedIndex === lastIndex) {
351+
if (this.lastCalcIndex === lastIndex) {
346352
return this.getIndexOffset(lastIndex) - this.getIndexOffset(end);
347353
} else {
348-
// if not, return a estimate padding.
354+
// if not, return a estimate offset.
349355
return (lastIndex - end) * this.getEstimateSize();
350356
}
351-
} // get estimate size for one item.
357+
} // get estimate size for one item, get from param.size at first range.
352358

353359
}, {
354360
key: "getEstimateSize",
@@ -400,6 +406,14 @@
400406
"default": 'vertical' // the other value is horizontal.
401407

402408
},
409+
upperThreshold: {
410+
type: Number,
411+
"default": 0
412+
},
413+
lowerThreshold: {
414+
type: Number,
415+
"default": 0
416+
},
403417
start: {
404418
type: Number,
405419
"default": 0
@@ -430,7 +444,7 @@
430444
},
431445
footerClass: {
432446
type: String,
433-
"default": 'div'
447+
"default": ''
434448
},
435449
disabled: {
436450
type: Boolean,
@@ -511,7 +525,7 @@
511525
},
512526
// tell parent current size identify by unqiue key.
513527
dispatchSizeChange: function dispatchSizeChange() {
514-
this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize());
528+
this.$parent.$emit(this.event, this.uniqueKey, this.getCurrentSize(), this.hasInitial);
515529
}
516530
}
517531
}; // wrapping for item.
@@ -552,7 +566,8 @@
552566
// string value also use for aria role attribute.
553567
FOOTER: 'footer'
554568
};
555-
var VirtualList = Vue.component('virtual-list', {
569+
var NAME = 'virtual-list';
570+
var VirtualList = Vue.component(NAME, {
556571
props: VirtualProps,
557572
data: function data() {
558573
return {
@@ -563,7 +578,7 @@
563578
dataSources: function dataSources(newValue, oldValue) {
564579
if (newValue.length !== oldValue.length) {
565580
this.virtual.updateParam('uniqueIds', this.getUniqueIdFromDataSources());
566-
this.virtual.handleDataSourcesLengthChange();
581+
this.virtual.handleDataSourcesChange();
567582
}
568583
}
569584
},
@@ -581,8 +596,8 @@
581596
// recommend for a third of keeps.
582597
uniqueIds: this.getUniqueIdFromDataSources()
583598
}, this.onRangeChanged); // just for debug
584-
585-
window.virtual = this.virtual; // also need sync initial range first.
599+
// window.virtual = this.virtual
600+
// also need sync initial range first.
586601

587602
this.range = this.virtual.getRange(); // listen item size changing.
588603

@@ -609,14 +624,16 @@
609624
this.virtual.saveSize(id, size);
610625
},
611626
// event called when slot mounted or size changed.
612-
onSlotResized: function onSlotResized(type, size) {
627+
onSlotResized: function onSlotResized(type, size, hasInit) {
613628
if (type === SLOT_TYPE.HEADER) {
614629
this.virtual.updateParam('slotHeaderSize', size);
615630
} else if (type === SLOT_TYPE.FOOTER) {
616631
this.virtual.updateParam('slotFooterSize', size);
617632
}
618633

619-
this.virtual.handleSlotSizeChange();
634+
if (hasInit) {
635+
this.virtual.handleSlotSizeChange();
636+
}
620637
},
621638
// here is the rerendering entry.
622639
onRangeChanged: function onRangeChanged(range) {
@@ -630,8 +647,8 @@
630647
}
631648

632649
var offset = root[this.directionKey];
633-
this.emitEvent(offset, evt);
634650
this.virtual.handleScroll(offset);
651+
this.emitEvent(offset, evt);
635652
},
636653
getUniqueIdFromDataSources: function getUniqueIdFromDataSources() {
637654
var _this = this;
@@ -653,15 +670,17 @@
653670
// ref element is definitely available here.
654671
var root = this.$refs.root;
655672
var range = this.virtual.getRange();
673+
var isLower = this.virtual.isLower();
674+
var isUpper = this.virtual.isUpper();
656675
var offsetShape = root[this.isHorizontal ? 'clientWidth' : 'clientHeight'];
657-
var scrollShape = root[this.isHorizontal ? 'scrollWidth' : 'scrollHeight']; // only non-empty & offset === 0 calls totop.
676+
var scrollShape = root[this.isHorizontal ? 'scrollWidth' : 'scrollHeight'];
658677

659-
if (!!this.dataSources.length && !offset) {
660-
this.$emit('totop', evt, range);
661-
} else if (offset + offsetShape >= scrollShape) {
662-
this.$emit('tobottom', evt, range);
678+
if (isUpper && !!this.dataSources.length && offset - this.upperThreshold <= 0) {
679+
this.$emit('toupper', evt, range);
680+
} else if (isLower && offset + offsetShape + this.lowerThreshold >= scrollShape) {
681+
this.$emit('tolower', evt, range);
663682
} else {
664-
this.$emit('onscroll', evt, range);
683+
this.$emit('scroll', evt, range);
665684
}
666685
},
667686
// get the real render slots based on range data.
@@ -671,17 +690,23 @@
671690
var end = this.disabled ? this.dataSources.length - 1 : this.range.end;
672691

673692
for (var index = start; index <= end; index++) {
674-
slots.push(h(Item, {
675-
"class": this.itemClass,
676-
props: {
677-
tag: this.itemTag,
678-
event: EVENT_TYPE.ITEM,
679-
horizontal: this.isHorizontal,
680-
uniqueKey: this.dataSources[index][this.dataKey],
681-
source: this.dataSources[index],
682-
component: this.dataComponent
683-
}
684-
}));
693+
var dataSource = this.dataSources[index];
694+
695+
if (dataSource) {
696+
slots.push(h(Item, {
697+
"class": this.itemClass,
698+
props: {
699+
tag: this.itemTag,
700+
event: EVENT_TYPE.ITEM,
701+
horizontal: this.isHorizontal,
702+
uniqueKey: dataSource[this.dataKey],
703+
source: dataSource,
704+
component: this.dataComponent
705+
}
706+
}));
707+
} else {
708+
console.warn("[".concat(NAME, "]: cannot get the index ").concat(index, " from data-sources."));
709+
}
685710
}
686711

687712
return slots;

0 commit comments

Comments
 (0)