tencent.jquery.pix.component 1.0.64 → 1.0.66-beta1
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 +166 -126
- 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, // 滚动事件回调函数
|
|
@@ -42,6 +43,8 @@ export function Waterfall(optionsInput = {}) {
|
|
|
42
43
|
|
|
43
44
|
this.$loadingNode = null;
|
|
44
45
|
|
|
46
|
+
this.isShowLoading = false; // 是否展示loading
|
|
47
|
+
|
|
45
48
|
|
|
46
49
|
// 间隔字符串转数字
|
|
47
50
|
if (options.columnGap.constructor === String) {
|
|
@@ -125,6 +128,7 @@ Waterfall.prototype.init = function () {
|
|
|
125
128
|
const self = this;
|
|
126
129
|
const options = this.options;
|
|
127
130
|
const $container = $(options.container);
|
|
131
|
+
const $scrollDom = options.scrollDom ? $(options.scrollDom) : $container;
|
|
128
132
|
|
|
129
133
|
this.nodePool = []; // DOM 节点池
|
|
130
134
|
this.activeNodes = new Map(); // 当前活跃节点(索引 -> DOM)
|
|
@@ -140,6 +144,7 @@ Waterfall.prototype.init = function () {
|
|
|
140
144
|
|
|
141
145
|
|
|
142
146
|
// 如果有定义loading函数 那么创建一个loading节点元素
|
|
147
|
+
console.log('options.createLoading', options.createLoading)
|
|
143
148
|
if (options.createLoading) {
|
|
144
149
|
this.$loadingNode = $(
|
|
145
150
|
`<div class="waterfall-loading" style="transform: translate(0px, -99999px)"></div>`
|
|
@@ -150,7 +155,7 @@ Waterfall.prototype.init = function () {
|
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
// 绑定滚动事件(节流处理)
|
|
153
|
-
$
|
|
158
|
+
$scrollDom.off().on('scroll', function () {
|
|
154
159
|
self.scrollTop = $(this).scrollTop();
|
|
155
160
|
|
|
156
161
|
window.requestAnimationFrame(() => {
|
|
@@ -162,7 +167,7 @@ Waterfall.prototype.init = function () {
|
|
|
162
167
|
}
|
|
163
168
|
});
|
|
164
169
|
|
|
165
|
-
this.scrollTop = $
|
|
170
|
+
this.scrollTop = $scrollDom.scrollTop(); // 当前滚动位置
|
|
166
171
|
|
|
167
172
|
// 首次渲染
|
|
168
173
|
self.updateVisibleItems();
|
|
@@ -173,11 +178,17 @@ Waterfall.prototype.init = function () {
|
|
|
173
178
|
Waterfall.prototype.updateVisibleItems = function (force = false) {
|
|
174
179
|
const self = this;
|
|
175
180
|
const options = this.options;
|
|
176
|
-
|
|
181
|
+
let h = 0;
|
|
182
|
+
if (options.scrollDom) {
|
|
183
|
+
h = $(options.scrollDom).height();
|
|
184
|
+
} else {
|
|
185
|
+
h = $(options.container).height();
|
|
186
|
+
}
|
|
177
187
|
|
|
178
188
|
const startTop = self.scrollTop; // 当前滚动位置
|
|
179
|
-
const endTop = startTop +
|
|
189
|
+
const endTop = startTop + h;
|
|
180
190
|
// console.log('startTop', startTop)
|
|
191
|
+
console.log('endTop', endTop)
|
|
181
192
|
|
|
182
193
|
// 进行可见区域的渲染更新
|
|
183
194
|
this.updateCardsInView({
|
|
@@ -228,13 +239,13 @@ Waterfall.prototype.appendCard = function (data, dataId, { top, left }) {
|
|
|
228
239
|
}
|
|
229
240
|
|
|
230
241
|
// 获取指定高度下的卡片索引
|
|
231
|
-
Waterfall.prototype.updateCardsInView = function ({ start, end, force = false }) {
|
|
242
|
+
Waterfall.prototype.updateCardsInView = async function ({ start, end, force = false }) {
|
|
232
243
|
const options = this.options;
|
|
233
244
|
const minHeight = this.getMinHeight();
|
|
234
245
|
const endBuffer = end + options.bufferHeight;
|
|
235
246
|
if (minHeight < endBuffer) {
|
|
236
247
|
// 如果不够 进行补建
|
|
237
|
-
this.createCards({ end: endBuffer });
|
|
248
|
+
await this.createCards({ end: endBuffer });
|
|
238
249
|
}
|
|
239
250
|
|
|
240
251
|
const startNum = start - options.bufferHeight;
|
|
@@ -400,123 +411,125 @@ Waterfall.prototype.getMinHeightColumn = function () {
|
|
|
400
411
|
}
|
|
401
412
|
|
|
402
413
|
// 创建卡片
|
|
403
|
-
Waterfall.prototype.createCards = function ({ end, dataId = -1 }) {
|
|
414
|
+
Waterfall.prototype.createCards = function ({ end, dataId = -1 }, callback) {
|
|
404
415
|
const self = this;
|
|
405
416
|
const options = this.options;
|
|
406
|
-
const $container = $(options.container);
|
|
407
417
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
418
|
+
return new Promise((resolve) => {
|
|
419
|
+
// 新方案:获取下一个未渲染的数据ID
|
|
420
|
+
let nextDataId = null;
|
|
421
|
+
for (let [dataId, dataInfo] of this.dataIdMap) {
|
|
422
|
+
if (!this.renderedDataIds.has(dataId)) {
|
|
423
|
+
nextDataId = dataId;
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
414
426
|
}
|
|
415
|
-
}
|
|
416
427
|
|
|
417
428
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const dataInfo = this.dataIdMap.get(nextDataId);
|
|
426
|
-
if (!dataInfo || !dataInfo.data) {
|
|
427
|
-
console.warn('Waterfall: Invalid data for dataId', nextDataId);
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
429
|
+
// 如果没有更多数据需要渲染
|
|
430
|
+
if (nextDataId === null) {
|
|
431
|
+
this.setScrollHeight();
|
|
432
|
+
return resolve();
|
|
433
|
+
}
|
|
430
434
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
435
|
+
const dataInfo = this.dataIdMap.get(nextDataId);
|
|
436
|
+
if (!dataInfo || !dataInfo.data) {
|
|
437
|
+
console.warn('Waterfall: Invalid data for dataId', nextDataId);
|
|
438
|
+
return resolve();
|
|
439
|
+
}
|
|
436
440
|
|
|
437
|
-
|
|
441
|
+
if (this.renderIndex >= options.data.length) {
|
|
442
|
+
this.setScrollHeight();
|
|
443
|
+
return resolve();
|
|
444
|
+
}
|
|
438
445
|
|
|
439
|
-
|
|
440
|
-
if (column === null) {
|
|
441
|
-
column = this.columnItems[0];
|
|
442
|
-
}
|
|
446
|
+
const data = options.data[nextDataId];
|
|
443
447
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
448
|
+
let column = this.getMinHeightColumn();
|
|
449
|
+
if (column === null) {
|
|
450
|
+
column = this.columnItems[0];
|
|
451
|
+
}
|
|
447
452
|
|
|
448
|
-
|
|
453
|
+
const top = column.bottom === 0 ? options.marginTop : (column.bottom + options.rowGap);
|
|
454
|
+
const position = { top, left: column.left };
|
|
455
|
+
const row = createDefaultRow(position);
|
|
449
456
|
|
|
450
|
-
|
|
457
|
+
this.renderIndex += 1;
|
|
451
458
|
|
|
452
|
-
|
|
453
|
-
if (options.shouldOccupySpace) {
|
|
454
|
-
specialNode = options.shouldOccupySpace(data) || false;
|
|
455
|
-
}
|
|
459
|
+
let specialNode = false;
|
|
456
460
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
$card = this.appendCard(data, nextDataId, position);
|
|
461
|
-
} else {
|
|
462
|
-
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
463
|
-
if ($tmp) {
|
|
464
|
-
$card = $tmp;
|
|
465
|
-
$card.css({
|
|
466
|
-
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
467
|
-
}).attr('data-index', nextDataId);
|
|
468
|
-
this.updateRenderUI($card, data, nextDataId);
|
|
469
|
-
} else {
|
|
470
|
-
$card = this.appendCard(data, nextDataId, position);
|
|
461
|
+
// 如果是特殊的卡片,需要指定节点不变更的数据,那么该数据的节点不能被其他数据使用
|
|
462
|
+
if (options.shouldOccupySpace) {
|
|
463
|
+
specialNode = options.shouldOccupySpace(data) || false;
|
|
471
464
|
}
|
|
472
465
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
466
|
+
// 添加卡片,使用dataId作为唯一标识
|
|
467
|
+
let $card = null;
|
|
468
|
+
if (this.nodePool.length === 0 || specialNode === true) {
|
|
469
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
470
|
+
} else {
|
|
471
|
+
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
472
|
+
if ($tmp) {
|
|
473
|
+
$card = $tmp;
|
|
474
|
+
$card.css({
|
|
475
|
+
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
476
|
+
}).attr('data-index', nextDataId);
|
|
477
|
+
this.updateRenderUI($card, data, nextDataId);
|
|
478
|
+
} else {
|
|
479
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
480
|
+
}
|
|
480
481
|
|
|
481
|
-
|
|
482
|
-
// dataInfo.layoutInfo = {
|
|
483
|
-
// //columnIndex: this.columnItems.indexOf(column),
|
|
484
|
-
// //position: position,
|
|
485
|
-
// // row: row
|
|
486
|
-
// };
|
|
482
|
+
}
|
|
487
483
|
|
|
484
|
+
row.$node = $card;
|
|
485
|
+
row.dataId = nextDataId; // 使用dataId替代renderIndex
|
|
486
|
+
if (dataId !== -1) {
|
|
487
|
+
row.dataId = dataId;
|
|
488
|
+
}
|
|
488
489
|
|
|
490
|
+
if (specialNode === false) {
|
|
491
|
+
// 把新增的卡片放进 activeNodes 当成活跃节点元素,那么是 可以动态使用的
|
|
492
|
+
this.activeNodes.set(nextDataId, $card);
|
|
489
493
|
|
|
494
|
+
this.allReadyNodes.set(nextDataId, $card);
|
|
495
|
+
} else {
|
|
496
|
+
// 如果是特殊的,这里不要记录了
|
|
497
|
+
this.allReadyNodes.set(nextDataId, null);
|
|
498
|
+
}
|
|
490
499
|
|
|
491
|
-
|
|
492
|
-
// 把新增的卡片放进 activeNodes 当成活跃节点元素,那么是 可以动态使用的
|
|
493
|
-
this.activeNodes.set(nextDataId, $card);
|
|
500
|
+
this.renderedDataIds.add(nextDataId);
|
|
494
501
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
502
|
+
setTimeout(() => {
|
|
503
|
+
window.requestAnimationFrame(() => {
|
|
504
|
+
// 更新列的底部距离
|
|
505
|
+
column.bottom = top + $card.height();
|
|
506
|
+
console.log('column.bottom', column.bottom, $card.height());
|
|
507
|
+
column.children.push(row);
|
|
508
|
+
row.bottom = column.bottom;
|
|
500
509
|
|
|
501
|
-
|
|
510
|
+
// 检查是否需要继续创建卡片
|
|
511
|
+
const minHeight = this.getMinHeight();
|
|
512
|
+
const hasMoreData = this.renderedDataIds.size < this.dataIdMap.size;
|
|
502
513
|
|
|
503
|
-
|
|
504
|
-
column.bottom = top + $card.height();
|
|
505
|
-
column.children.push(row);
|
|
506
|
-
row.bottom = column.bottom;
|
|
514
|
+
if (hasMoreData && (minHeight < end)) {
|
|
507
515
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
516
|
+
this.createCards({ end }, () => {
|
|
517
|
+
resolve();
|
|
518
|
+
if (callback) {
|
|
519
|
+
callback();
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
} else {
|
|
523
|
+
this.setScrollHeight();
|
|
524
|
+
resolve();
|
|
525
|
+
if (callback) {
|
|
526
|
+
callback();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
}, 42);
|
|
531
|
+
});
|
|
511
532
|
|
|
512
|
-
if (hasMoreData && (minHeight < end)) {
|
|
513
|
-
window.requestAnimationFrame(() => {
|
|
514
|
-
this.createCards({ end });
|
|
515
|
-
});
|
|
516
|
-
} else {
|
|
517
|
-
const maxHeight = this.getMaxHeight();
|
|
518
|
-
$(options.container).find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
519
|
-
}
|
|
520
533
|
}
|
|
521
534
|
|
|
522
535
|
|
|
@@ -559,7 +572,7 @@ Waterfall.prototype.updateRenderUI = function ($node, data, dataId) {
|
|
|
559
572
|
|
|
560
573
|
|
|
561
574
|
|
|
562
|
-
Waterfall.prototype.updateData = function (newData) {
|
|
575
|
+
Waterfall.prototype.updateData = async function (newData) {
|
|
563
576
|
const options = this.options;
|
|
564
577
|
options.data = newData;
|
|
565
578
|
|
|
@@ -569,23 +582,45 @@ Waterfall.prototype.updateData = function (newData) {
|
|
|
569
582
|
//this.nextDataId = 0;
|
|
570
583
|
|
|
571
584
|
// 为每个数据项分配唯一ID
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
this.createCards({ end: 0, dataId });
|
|
585
|
+
let bool = true
|
|
586
|
+
let count = options.data.length - 1;
|
|
587
|
+
let index = 0;
|
|
588
|
+
|
|
589
|
+
while (bool) {
|
|
590
|
+
if (index > count) {
|
|
591
|
+
bool = false
|
|
592
|
+
this.updateVisibleItems(true); // 强制更新渲染
|
|
593
|
+
break;
|
|
582
594
|
}
|
|
583
|
-
});
|
|
584
595
|
|
|
585
|
-
|
|
596
|
+
const dataId = index;
|
|
597
|
+
this.dataIdMap.set(dataId, {
|
|
598
|
+
data: true,
|
|
599
|
+
originalIndex: dataId,
|
|
600
|
+
layoutInfo: null
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
await this.createCards({ end: 0, dataId })
|
|
604
|
+
|
|
605
|
+
index += 1;
|
|
606
|
+
|
|
607
|
+
}
|
|
608
|
+
// options.data.forEach((item, index) => {
|
|
609
|
+
// const dataId = index; // this.nextDataId++;
|
|
610
|
+
// if (!this.allReadyNodes.has(dataId)) {
|
|
611
|
+
// this.dataIdMap.set(dataId, {
|
|
612
|
+
// data: true,// item,
|
|
613
|
+
// originalIndex: index,
|
|
614
|
+
// layoutInfo: null // 将在布局时填充
|
|
615
|
+
// });
|
|
616
|
+
// // 如果没有准备好这个数据,这里要创建一个占位节点
|
|
617
|
+
// this.createCards({ end: 0, dataId });
|
|
618
|
+
// }
|
|
619
|
+
// });
|
|
620
|
+
|
|
621
|
+
// this.updateVisibleItems(true); // 强制更新渲染
|
|
622
|
+
|
|
586
623
|
|
|
587
|
-
// 重新计算所有卡片位置并更新位置
|
|
588
|
-
// this.updatePointCards();
|
|
589
624
|
}
|
|
590
625
|
|
|
591
626
|
// 某个数据进行了UI变更,触发高度重新绘制
|
|
@@ -695,26 +730,23 @@ Waterfall.prototype.updatePointCards = function () {
|
|
|
695
730
|
|
|
696
731
|
// 展示loading的回调函数
|
|
697
732
|
Waterfall.prototype.showLoading = function (callback = null) {
|
|
733
|
+
this.isShowLoading = true;
|
|
698
734
|
const options = this.options;
|
|
699
|
-
const $container = $(options.container);
|
|
700
735
|
let $node = null
|
|
701
736
|
if (this.$loadingNode) {
|
|
702
737
|
let loadingTop = this.getMaxHeight() + options.rowGap
|
|
703
|
-
let h = loadingTop + this.$loadingNode.height() + options.marginBottom
|
|
704
|
-
|
|
705
738
|
this.$loadingNode.css('transform', `translate(0px,${loadingTop}px)`);
|
|
706
|
-
$(options.container).find('.waterfall-list-scroll').css('height', h + 'px');
|
|
707
|
-
|
|
708
739
|
$node = this.$loadingNode
|
|
709
740
|
}
|
|
710
741
|
|
|
711
742
|
if (callback) callback($node)
|
|
743
|
+
this.setScrollHeight();
|
|
712
744
|
}
|
|
713
745
|
|
|
714
746
|
// 隐藏loading的回调函数
|
|
715
747
|
Waterfall.prototype.hideLoading = function (callback = null) {
|
|
748
|
+
this.isShowLoading = false;
|
|
716
749
|
const options = this.options;
|
|
717
|
-
const $container = $(options.container);
|
|
718
750
|
let $node = null
|
|
719
751
|
if (this.$loadingNode) {
|
|
720
752
|
let h1 = this.getMaxHeight() + options.marginBottom
|
|
@@ -722,19 +754,27 @@ Waterfall.prototype.hideLoading = function (callback = null) {
|
|
|
722
754
|
//如果要设置高度,那么这里判断一下当前是否正在做updata 一般这里被调用时,数据已经读到,在updata的同一时间调用了该函数
|
|
723
755
|
// 如果两个时刻高度是一致的 那么数据就是一致的 这里重新设置回来高度即可
|
|
724
756
|
window.requestAnimationFrame(() => {
|
|
725
|
-
|
|
726
|
-
if (h1 === h2) {
|
|
727
|
-
const $scroll = $(options.container).find('.waterfall-list-scroll')
|
|
728
|
-
const h = $scroll.height()
|
|
729
|
-
if (h !== h1) {
|
|
730
|
-
$scroll.css('height', h1 + 'px');
|
|
731
|
-
}
|
|
732
|
-
}
|
|
757
|
+
this.setScrollHeight();
|
|
733
758
|
})
|
|
734
759
|
$node = this.$loadingNode
|
|
735
760
|
}
|
|
736
761
|
|
|
737
762
|
if (callback) callback($node)
|
|
763
|
+
this.setScrollHeight();
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// 设置滚动条列表的高度
|
|
767
|
+
Waterfall.prototype.setScrollHeight = function () {
|
|
768
|
+
const options = this.options;
|
|
769
|
+
const $container = $(options.container);
|
|
770
|
+
let h = this.getMaxHeight();
|
|
771
|
+
if (this.isShowLoading === true) {
|
|
772
|
+
if (this.$loadingNode) {
|
|
773
|
+
h += options.rowGap + this.$loadingNode.height();
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
h += options.marginBottom;
|
|
777
|
+
$container.find('.waterfall-list-scroll').css('height', h + 'px');
|
|
738
778
|
}
|
|
739
779
|
|
|
740
780
|
function createDefaultRow({ top, left }) {
|