tencent.jquery.pix.component 1.0.65 → 1.0.66-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/waterfall/waterfall.js +154 -124
- package/package.json +1 -1
|
@@ -17,6 +17,7 @@ const DEFAULTS = {
|
|
|
17
17
|
renderItem(data, index) { // 元素首次渲染时的回调函数, 如果把updateItem设置为空,那么更新时则会兜底触发renderItem
|
|
18
18
|
return '<div class="waterfall-item"></div>';
|
|
19
19
|
},
|
|
20
|
+
scrollDom: null, // 滚动元素,如果传入了滚动元素,那么用来计算的窗口高度就以滚动元素的高度为准
|
|
20
21
|
// 传入 $node, data, index
|
|
21
22
|
updateItem: null, // 元素更新时的回调函数
|
|
22
23
|
onscroll: null, // 滚动事件回调函数
|
|
@@ -127,6 +128,7 @@ Waterfall.prototype.init = function () {
|
|
|
127
128
|
const self = this;
|
|
128
129
|
const options = this.options;
|
|
129
130
|
const $container = $(options.container);
|
|
131
|
+
const $scrollDom = options.scrollDom ? $(options.scrollDom) : $container;
|
|
130
132
|
|
|
131
133
|
this.nodePool = []; // DOM 节点池
|
|
132
134
|
this.activeNodes = new Map(); // 当前活跃节点(索引 -> DOM)
|
|
@@ -153,7 +155,7 @@ Waterfall.prototype.init = function () {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
// 绑定滚动事件(节流处理)
|
|
156
|
-
$
|
|
158
|
+
$scrollDom.off().on('scroll', function () {
|
|
157
159
|
self.scrollTop = $(this).scrollTop();
|
|
158
160
|
|
|
159
161
|
window.requestAnimationFrame(() => {
|
|
@@ -165,7 +167,7 @@ Waterfall.prototype.init = function () {
|
|
|
165
167
|
}
|
|
166
168
|
});
|
|
167
169
|
|
|
168
|
-
this.scrollTop = $
|
|
170
|
+
this.scrollTop = $scrollDom.scrollTop(); // 当前滚动位置
|
|
169
171
|
|
|
170
172
|
// 首次渲染
|
|
171
173
|
self.updateVisibleItems();
|
|
@@ -175,12 +177,20 @@ Waterfall.prototype.init = function () {
|
|
|
175
177
|
// force 强制更新渲染
|
|
176
178
|
Waterfall.prototype.updateVisibleItems = function (force = false) {
|
|
177
179
|
const self = this;
|
|
180
|
+
|
|
178
181
|
const options = this.options;
|
|
179
|
-
|
|
182
|
+
let h = 0;
|
|
183
|
+
if (options.scrollDom) {
|
|
184
|
+
h = $(options.scrollDom).height();
|
|
185
|
+
} else {
|
|
186
|
+
h = $(options.container).height();
|
|
187
|
+
}
|
|
180
188
|
|
|
181
189
|
const startTop = self.scrollTop; // 当前滚动位置
|
|
182
|
-
const endTop = startTop +
|
|
190
|
+
const endTop = startTop + h;
|
|
191
|
+
|
|
183
192
|
// console.log('startTop', startTop)
|
|
193
|
+
console.log('endTop', endTop)
|
|
184
194
|
|
|
185
195
|
// 进行可见区域的渲染更新
|
|
186
196
|
this.updateCardsInView({
|
|
@@ -231,13 +241,13 @@ Waterfall.prototype.appendCard = function (data, dataId, { top, left }) {
|
|
|
231
241
|
}
|
|
232
242
|
|
|
233
243
|
// 获取指定高度下的卡片索引
|
|
234
|
-
Waterfall.prototype.updateCardsInView = function ({ start, end, force = false }) {
|
|
244
|
+
Waterfall.prototype.updateCardsInView = async function ({ start, end, force = false }) {
|
|
235
245
|
const options = this.options;
|
|
236
246
|
const minHeight = this.getMinHeight();
|
|
237
247
|
const endBuffer = end + options.bufferHeight;
|
|
238
248
|
if (minHeight < endBuffer) {
|
|
239
249
|
// 如果不够 进行补建
|
|
240
|
-
this.createCards({ end: endBuffer });
|
|
250
|
+
await this.createCards({ end: endBuffer });
|
|
241
251
|
}
|
|
242
252
|
|
|
243
253
|
const startNum = start - options.bufferHeight;
|
|
@@ -403,124 +413,127 @@ Waterfall.prototype.getMinHeightColumn = function () {
|
|
|
403
413
|
}
|
|
404
414
|
|
|
405
415
|
// 创建卡片
|
|
406
|
-
|
|
416
|
+
|
|
417
|
+
Waterfall.prototype.createCards = function ({ end, dataId = -1 }, callback) {
|
|
407
418
|
const self = this;
|
|
419
|
+
|
|
408
420
|
const options = this.options;
|
|
409
|
-
const $container = $(options.container);
|
|
410
421
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
422
|
+
return new Promise((resolve) => {
|
|
423
|
+
// 新方案:获取下一个未渲染的数据ID
|
|
424
|
+
let nextDataId = null;
|
|
425
|
+
for (let [dataId, dataInfo] of this.dataIdMap) {
|
|
426
|
+
if (!this.renderedDataIds.has(dataId)) {
|
|
427
|
+
nextDataId = dataId;
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
417
430
|
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
431
|
|
|
421
|
-
// 如果没有更多数据需要渲染
|
|
422
|
-
if (nextDataId === null) {
|
|
423
|
-
// const maxHeight = this.getMaxHeight();
|
|
424
|
-
// $container.find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
425
|
-
this.setScrollHeight();
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
432
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
433
|
+
// 如果没有更多数据需要渲染
|
|
434
|
+
if (nextDataId === null) {
|
|
435
|
+
this.setScrollHeight();
|
|
436
|
+
return resolve();
|
|
437
|
+
}
|
|
434
438
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
+
const dataInfo = this.dataIdMap.get(nextDataId);
|
|
440
|
+
if (!dataInfo || !dataInfo.data) {
|
|
441
|
+
console.warn('Waterfall: Invalid data for dataId', nextDataId);
|
|
442
|
+
return resolve();
|
|
443
|
+
}
|
|
439
444
|
|
|
440
|
-
|
|
445
|
+
if (this.renderIndex >= options.data.length) {
|
|
446
|
+
this.setScrollHeight();
|
|
447
|
+
return resolve();
|
|
448
|
+
}
|
|
441
449
|
|
|
442
|
-
|
|
443
|
-
if (column === null) {
|
|
444
|
-
column = this.columnItems[0];
|
|
445
|
-
}
|
|
450
|
+
const data = options.data[nextDataId];
|
|
446
451
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
452
|
+
let column = this.getMinHeightColumn();
|
|
453
|
+
if (column === null) {
|
|
454
|
+
column = this.columnItems[0];
|
|
455
|
+
}
|
|
450
456
|
|
|
451
|
-
|
|
457
|
+
const top = column.bottom === 0 ? options.marginTop : (column.bottom + options.rowGap);
|
|
458
|
+
const position = { top, left: column.left };
|
|
459
|
+
const row = createDefaultRow(position);
|
|
452
460
|
|
|
453
|
-
|
|
461
|
+
this.renderIndex += 1;
|
|
454
462
|
|
|
455
|
-
|
|
456
|
-
if (options.shouldOccupySpace) {
|
|
457
|
-
specialNode = options.shouldOccupySpace(data) || false;
|
|
458
|
-
}
|
|
463
|
+
let specialNode = false;
|
|
459
464
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
$card = this.appendCard(data, nextDataId, position);
|
|
464
|
-
} else {
|
|
465
|
-
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
466
|
-
if ($tmp) {
|
|
467
|
-
$card = $tmp;
|
|
468
|
-
$card.css({
|
|
469
|
-
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
470
|
-
}).attr('data-index', nextDataId);
|
|
471
|
-
this.updateRenderUI($card, data, nextDataId);
|
|
472
|
-
} else {
|
|
473
|
-
$card = this.appendCard(data, nextDataId, position);
|
|
465
|
+
// 如果是特殊的卡片,需要指定节点不变更的数据,那么该数据的节点不能被其他数据使用
|
|
466
|
+
if (options.shouldOccupySpace) {
|
|
467
|
+
specialNode = options.shouldOccupySpace(data) || false;
|
|
474
468
|
}
|
|
475
469
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
470
|
+
// 添加卡片,使用dataId作为唯一标识
|
|
471
|
+
let $card = null;
|
|
472
|
+
if (this.nodePool.length === 0 || specialNode === true) {
|
|
473
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
474
|
+
} else {
|
|
475
|
+
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
476
|
+
if ($tmp) {
|
|
477
|
+
$card = $tmp;
|
|
478
|
+
$card.css({
|
|
479
|
+
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
480
|
+
}).attr('data-index', nextDataId);
|
|
481
|
+
this.updateRenderUI($card, data, nextDataId);
|
|
482
|
+
} else {
|
|
483
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
484
|
+
}
|
|
483
485
|
|
|
484
|
-
|
|
485
|
-
// dataInfo.layoutInfo = {
|
|
486
|
-
// //columnIndex: this.columnItems.indexOf(column),
|
|
487
|
-
// //position: position,
|
|
488
|
-
// // row: row
|
|
489
|
-
// };
|
|
486
|
+
}
|
|
490
487
|
|
|
488
|
+
row.$node = $card;
|
|
489
|
+
row.dataId = nextDataId; // 使用dataId替代renderIndex
|
|
490
|
+
if (dataId !== -1) {
|
|
491
|
+
row.dataId = dataId;
|
|
492
|
+
}
|
|
491
493
|
|
|
494
|
+
if (specialNode === false) {
|
|
495
|
+
// 把新增的卡片放进 activeNodes 当成活跃节点元素,那么是 可以动态使用的
|
|
496
|
+
this.activeNodes.set(nextDataId, $card);
|
|
492
497
|
|
|
498
|
+
this.allReadyNodes.set(nextDataId, $card);
|
|
499
|
+
} else {
|
|
500
|
+
// 如果是特殊的,这里不要记录了
|
|
501
|
+
this.allReadyNodes.set(nextDataId, null);
|
|
502
|
+
}
|
|
493
503
|
|
|
494
|
-
|
|
495
|
-
// 把新增的卡片放进 activeNodes 当成活跃节点元素,那么是 可以动态使用的
|
|
496
|
-
this.activeNodes.set(nextDataId, $card);
|
|
504
|
+
this.renderedDataIds.add(nextDataId);
|
|
497
505
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
506
|
+
setTimeout(() => {
|
|
507
|
+
window.requestAnimationFrame(() => {
|
|
508
|
+
// 更新列的底部距离
|
|
509
|
+
column.bottom = top + $card.height();
|
|
510
|
+
console.log('column.bottom', column.bottom, $card.height());
|
|
511
|
+
column.children.push(row);
|
|
512
|
+
row.bottom = column.bottom;
|
|
503
513
|
|
|
504
|
-
|
|
514
|
+
// 检查是否需要继续创建卡片
|
|
515
|
+
const minHeight = this.getMinHeight();
|
|
516
|
+
const hasMoreData = this.renderedDataIds.size < this.dataIdMap.size;
|
|
505
517
|
|
|
506
|
-
|
|
507
|
-
column.bottom = top + $card.height();
|
|
508
|
-
column.children.push(row);
|
|
509
|
-
row.bottom = column.bottom;
|
|
518
|
+
if (hasMoreData && (minHeight < end)) {
|
|
510
519
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
520
|
+
this.createCards({ end }, () => {
|
|
521
|
+
resolve();
|
|
522
|
+
if (callback) {
|
|
523
|
+
callback();
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
} else {
|
|
527
|
+
this.setScrollHeight();
|
|
528
|
+
resolve();
|
|
529
|
+
if (callback) {
|
|
530
|
+
callback();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
}, 42);
|
|
535
|
+
});
|
|
514
536
|
|
|
515
|
-
if (hasMoreData && (minHeight < end)) {
|
|
516
|
-
window.requestAnimationFrame(() => {
|
|
517
|
-
this.createCards({ end });
|
|
518
|
-
});
|
|
519
|
-
} else {
|
|
520
|
-
// const maxHeight = this.getMaxHeight();
|
|
521
|
-
// $(options.container).find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
522
|
-
this.setScrollHeight();
|
|
523
|
-
}
|
|
524
537
|
}
|
|
525
538
|
|
|
526
539
|
|
|
@@ -563,7 +576,7 @@ Waterfall.prototype.updateRenderUI = function ($node, data, dataId) {
|
|
|
563
576
|
|
|
564
577
|
|
|
565
578
|
|
|
566
|
-
Waterfall.prototype.updateData = function (newData) {
|
|
579
|
+
Waterfall.prototype.updateData = async function (newData) {
|
|
567
580
|
const options = this.options;
|
|
568
581
|
options.data = newData;
|
|
569
582
|
|
|
@@ -573,23 +586,45 @@ Waterfall.prototype.updateData = function (newData) {
|
|
|
573
586
|
//this.nextDataId = 0;
|
|
574
587
|
|
|
575
588
|
// 为每个数据项分配唯一ID
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
this.createCards({ end: 0, dataId });
|
|
589
|
+
let bool = true
|
|
590
|
+
let count = options.data.length - 1;
|
|
591
|
+
let index = 0;
|
|
592
|
+
|
|
593
|
+
while (bool) {
|
|
594
|
+
if (index > count) {
|
|
595
|
+
bool = false
|
|
596
|
+
this.updateVisibleItems(true); // 强制更新渲染
|
|
597
|
+
break;
|
|
586
598
|
}
|
|
587
|
-
});
|
|
588
599
|
|
|
589
|
-
|
|
600
|
+
const dataId = index;
|
|
601
|
+
this.dataIdMap.set(dataId, {
|
|
602
|
+
data: true,
|
|
603
|
+
originalIndex: dataId,
|
|
604
|
+
layoutInfo: null
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
await this.createCards({ end: 0, dataId })
|
|
608
|
+
|
|
609
|
+
index += 1;
|
|
610
|
+
|
|
611
|
+
}
|
|
612
|
+
// options.data.forEach((item, index) => {
|
|
613
|
+
// const dataId = index; // this.nextDataId++;
|
|
614
|
+
// if (!this.allReadyNodes.has(dataId)) {
|
|
615
|
+
// this.dataIdMap.set(dataId, {
|
|
616
|
+
// data: true,// item,
|
|
617
|
+
// originalIndex: index,
|
|
618
|
+
// layoutInfo: null // 将在布局时填充
|
|
619
|
+
// });
|
|
620
|
+
// // 如果没有准备好这个数据,这里要创建一个占位节点
|
|
621
|
+
// this.createCards({ end: 0, dataId });
|
|
622
|
+
// }
|
|
623
|
+
// });
|
|
624
|
+
|
|
625
|
+
// this.updateVisibleItems(true); // 强制更新渲染
|
|
626
|
+
|
|
590
627
|
|
|
591
|
-
// 重新计算所有卡片位置并更新位置
|
|
592
|
-
// this.updatePointCards();
|
|
593
628
|
}
|
|
594
629
|
|
|
595
630
|
// 某个数据进行了UI变更,触发高度重新绘制
|
|
@@ -701,12 +736,16 @@ Waterfall.prototype.updatePointCards = function () {
|
|
|
701
736
|
Waterfall.prototype.showLoading = function (callback = null) {
|
|
702
737
|
this.isShowLoading = true;
|
|
703
738
|
const options = this.options;
|
|
704
|
-
const $container = $(options.container);
|
|
705
739
|
let $node = null
|
|
706
740
|
if (this.$loadingNode) {
|
|
707
741
|
let loadingTop = this.getMaxHeight() + options.rowGap
|
|
708
742
|
this.$loadingNode.css('transform', `translate(0px,${loadingTop}px)`);
|
|
709
|
-
$node = this.$loadingNode
|
|
743
|
+
$node = this.$loadingNode;
|
|
744
|
+
window.requestAnimationFrame(() => {
|
|
745
|
+
setTimeout(() => {
|
|
746
|
+
this.$scrollDom.scrollTop(loadingTop + this.$loadingNode.height());
|
|
747
|
+
});
|
|
748
|
+
});
|
|
710
749
|
}
|
|
711
750
|
|
|
712
751
|
if (callback) callback($node)
|
|
@@ -717,7 +756,6 @@ Waterfall.prototype.showLoading = function (callback = null) {
|
|
|
717
756
|
Waterfall.prototype.hideLoading = function (callback = null) {
|
|
718
757
|
this.isShowLoading = false;
|
|
719
758
|
const options = this.options;
|
|
720
|
-
const $container = $(options.container);
|
|
721
759
|
let $node = null
|
|
722
760
|
if (this.$loadingNode) {
|
|
723
761
|
let h1 = this.getMaxHeight() + options.marginBottom
|
|
@@ -725,14 +763,6 @@ Waterfall.prototype.hideLoading = function (callback = null) {
|
|
|
725
763
|
//如果要设置高度,那么这里判断一下当前是否正在做updata 一般这里被调用时,数据已经读到,在updata的同一时间调用了该函数
|
|
726
764
|
// 如果两个时刻高度是一致的 那么数据就是一致的 这里重新设置回来高度即可
|
|
727
765
|
window.requestAnimationFrame(() => {
|
|
728
|
-
// let h2 = this.getMaxHeight() + options.marginBottom
|
|
729
|
-
// if (h1 === h2) {
|
|
730
|
-
// const $scroll = $(options.container).find('.waterfall-list-scroll')
|
|
731
|
-
// const h = $scroll.height()
|
|
732
|
-
// if (h !== h1) {
|
|
733
|
-
// $scroll.css('height', h1 + 'px');
|
|
734
|
-
// }
|
|
735
|
-
// }
|
|
736
766
|
this.setScrollHeight();
|
|
737
767
|
})
|
|
738
768
|
$node = this.$loadingNode
|