tencent.jquery.pix.component 1.0.90 → 1.0.91-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/change.md +4 -0
- package/components/waterfallv2/waterfallv2.js +104 -72
- package/package.json +1 -1
package/change.md
CHANGED
|
@@ -176,25 +176,32 @@ Waterfallv2.prototype.init = function (optionsMain = null) {
|
|
|
176
176
|
</div>
|
|
177
177
|
`);
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
// 【优化】缓存 DOM 引用,避免每次都执行 jQuery find 查询
|
|
180
|
+
this.$scrollWrapper = $container.find('.waterfallv2-list-scroll');
|
|
181
|
+
this.$viewport = $container.find('.Waterfallv2-list-viewport');
|
|
180
182
|
|
|
181
183
|
// 如果有定义loading函数 那么创建一个loading节点元素
|
|
182
184
|
if (options.createLoading) {
|
|
183
185
|
this.$loadingNode = $(
|
|
184
186
|
`<div class="waterfallv2-loading" style="position:absolute;top:0;left:0;width:100%;transform: translate(0px, -99999px)"></div>`
|
|
185
187
|
);
|
|
186
|
-
|
|
188
|
+
this.$viewport.append(this.$loadingNode);
|
|
187
189
|
|
|
188
190
|
options.createLoading(this.$loadingNode);
|
|
189
191
|
}
|
|
190
192
|
|
|
191
|
-
//
|
|
193
|
+
// 绑定滚动事件(真正的 rAF 节流:一帧内只执行一次 updateVisibleItems)
|
|
194
|
+
this._rafPending = false;
|
|
192
195
|
$scrollDom.off().on('scroll', function () {
|
|
193
196
|
self.scrollTop = $(this).scrollTop();
|
|
194
197
|
|
|
195
|
-
|
|
196
|
-
self.
|
|
197
|
-
|
|
198
|
+
if (!self._rafPending) {
|
|
199
|
+
self._rafPending = true;
|
|
200
|
+
window.requestAnimationFrame(() => {
|
|
201
|
+
self._rafPending = false;
|
|
202
|
+
self.updateVisibleItems();
|
|
203
|
+
});
|
|
204
|
+
}
|
|
198
205
|
|
|
199
206
|
if (options.onscroll && options.onscroll.constructor === Function) {
|
|
200
207
|
options.onscroll(this, self.scrollTop);
|
|
@@ -451,8 +458,7 @@ Waterfallv2.prototype.updateVisibleItems = function (force = false) {
|
|
|
451
458
|
// 新增卡片
|
|
452
459
|
Waterfallv2.prototype.appendCard = function (data, dataId, { top, left }) {
|
|
453
460
|
const options = this.options;
|
|
454
|
-
const $
|
|
455
|
-
const $viewport = $container.find('.Waterfallv2-list-viewport');
|
|
461
|
+
const $viewport = this.$viewport;
|
|
456
462
|
|
|
457
463
|
if (!this.dataIdMap.has(dataId)) {
|
|
458
464
|
console.error('Waterfallv2: Invalid dataId in appendCard', dataId);
|
|
@@ -499,13 +505,30 @@ Waterfallv2.prototype.updateCardsInView = async function ({ start, end, force =
|
|
|
499
505
|
|
|
500
506
|
const startNum = start - options.bufferHeight;
|
|
501
507
|
const endNum = end + options.bufferHeight;
|
|
508
|
+
|
|
509
|
+
// 【优化】构建 dataId -> {data, index} 的快速查找 Map,避免每个 row 都执行 O(n) 的 Array.find 和 indexOf
|
|
510
|
+
const dataLookupMap = new Map();
|
|
511
|
+
for (let i = 0; i < options.data.length; i++) {
|
|
512
|
+
const item = options.data[i];
|
|
513
|
+
dataLookupMap.set(item.dataId, { data: item, index: i });
|
|
514
|
+
}
|
|
515
|
+
|
|
502
516
|
// 新方案:基于数据ID映射机制
|
|
503
517
|
const newActiveNodes = new Map();
|
|
518
|
+
// 【优化】用 Set 存储已使用的节点引用,替代 hasNodeInActives 的 O(n) 遍历
|
|
519
|
+
const usedNodeSet = new Set();
|
|
520
|
+
|
|
504
521
|
for (let i = 0; i < this.columns; i++) {
|
|
505
522
|
const column = this.columnItems[i];
|
|
506
523
|
|
|
507
524
|
for (let j = 0; j < column.children.length; j++) {
|
|
508
525
|
const row = column.children[j];
|
|
526
|
+
|
|
527
|
+
// 【优化】提前退出:column.children 按 top 排序,当 row.top > endNum 时后续都不可见
|
|
528
|
+
if (row.top > endNum) {
|
|
529
|
+
break;
|
|
530
|
+
}
|
|
531
|
+
|
|
509
532
|
const dataId = row.dataId; // 使用dataId替代renderIndex
|
|
510
533
|
|
|
511
534
|
// 验证数据ID有效性
|
|
@@ -521,8 +544,10 @@ Waterfallv2.prototype.updateCardsInView = async function ({ start, end, force =
|
|
|
521
544
|
continue;
|
|
522
545
|
}
|
|
523
546
|
|
|
524
|
-
//
|
|
525
|
-
const
|
|
547
|
+
// 【优化】通过 Map O(1) 查找替代 Array.find O(n)
|
|
548
|
+
const _lookup = dataLookupMap.get(dataId);
|
|
549
|
+
const data = _lookup ? _lookup.data : undefined;
|
|
550
|
+
const _dataIndex = _lookup ? _lookup.index : -1;
|
|
526
551
|
|
|
527
552
|
// 如果当前这个节点是特殊节点,只更新位置,不参与节点复用
|
|
528
553
|
let specialNode = false;
|
|
@@ -537,7 +562,7 @@ Waterfallv2.prototype.updateCardsInView = async function ({ start, end, force =
|
|
|
537
562
|
}).attr('data-index', dataId);
|
|
538
563
|
|
|
539
564
|
if (force) {
|
|
540
|
-
this.updateRenderUI(row.$node, data, dataId);
|
|
565
|
+
this.updateRenderUI(row.$node, data, dataId, _dataIndex);
|
|
541
566
|
}
|
|
542
567
|
} else {
|
|
543
568
|
console.warn('Waterfallv2: Special node DOM not found for dataId', dataId);
|
|
@@ -545,67 +570,68 @@ Waterfallv2.prototype.updateCardsInView = async function ({ start, end, force =
|
|
|
545
570
|
continue;
|
|
546
571
|
}
|
|
547
572
|
|
|
573
|
+
// 跳过不在可视区域的 row(top 在 startNum 之前的)
|
|
574
|
+
if (row.bottom < startNum) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
|
|
548
578
|
// 在可视区域内 进行有关卡片的操作
|
|
549
|
-
const
|
|
550
|
-
if (bool) {
|
|
551
|
-
const $card = this.activeNodes.get(dataId);
|
|
579
|
+
const $card = this.activeNodes.get(dataId);
|
|
552
580
|
|
|
553
|
-
|
|
581
|
+
let $node = null;
|
|
554
582
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
583
|
+
// 【优化】用 Set.has() O(1) 替代 hasNodeInActives 的 Map.forEach O(n)
|
|
584
|
+
let isCardUsed = true;
|
|
585
|
+
if ($card) {
|
|
586
|
+
isCardUsed = usedNodeSet.has($card);
|
|
587
|
+
}
|
|
588
|
+
if (isCardUsed === false) {
|
|
589
|
+
$node = $card;
|
|
590
|
+
this.activeNodes.delete(dataId);
|
|
591
|
+
if (force) {
|
|
592
|
+
this.updateRenderUI($node, data, dataId, _dataIndex);
|
|
558
593
|
}
|
|
559
|
-
if (bool === false) {
|
|
560
|
-
$node = $card;
|
|
561
|
-
this.activeNodes.delete(dataId);
|
|
562
|
-
if (force) {
|
|
563
|
-
this.updateRenderUI($node, data, dataId);
|
|
564
|
-
}
|
|
565
594
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
595
|
+
} else {
|
|
596
|
+
const $readyCard = this.allReadyNodes.get(dataId);
|
|
597
|
+
let isReadyUsed = true;
|
|
598
|
+
if ($readyCard) {
|
|
599
|
+
isReadyUsed = usedNodeSet.has($readyCard);
|
|
600
|
+
}
|
|
601
|
+
if (isReadyUsed === false) {
|
|
602
|
+
$node = $readyCard;
|
|
603
|
+
this.updateRenderUI($node, data, dataId, _dataIndex);
|
|
575
604
|
|
|
605
|
+
} else {
|
|
606
|
+
$node = getNodePoolPop(this.nodePool, usedNodeSet);
|
|
607
|
+
if ($node === null) {
|
|
608
|
+
$node = this.appendCard(data, dataId, {
|
|
609
|
+
top: row.top, left: row.left
|
|
610
|
+
});
|
|
611
|
+
row.$node = $node;
|
|
576
612
|
} else {
|
|
577
|
-
$node
|
|
578
|
-
|
|
579
|
-
$node = this.appendCard(data, dataId, {
|
|
580
|
-
top: row.top, left: row.left
|
|
581
|
-
});
|
|
582
|
-
row.$node = $node;
|
|
583
|
-
} else {
|
|
584
|
-
this.updateRenderUI($node, data, dataId);
|
|
585
|
-
row.$node = $node;
|
|
586
|
-
}
|
|
613
|
+
this.updateRenderUI($node, data, dataId, _dataIndex);
|
|
614
|
+
row.$node = $node;
|
|
587
615
|
}
|
|
588
616
|
}
|
|
589
|
-
$node.css({
|
|
590
|
-
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
591
|
-
}).attr('data-index', dataId);
|
|
592
|
-
|
|
593
|
-
newActiveNodes.set(dataId, $node);
|
|
594
|
-
|
|
595
|
-
// 清除掉在NodePool中的card
|
|
596
|
-
const index = this.nodePool.indexOf($card);
|
|
597
|
-
if (index !== -1) {
|
|
598
|
-
this.nodePool.splice(index, 1);
|
|
599
|
-
}
|
|
600
617
|
}
|
|
618
|
+
$node.css({
|
|
619
|
+
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
620
|
+
}).attr('data-index', dataId);
|
|
621
|
+
|
|
622
|
+
newActiveNodes.set(dataId, $node);
|
|
623
|
+
usedNodeSet.add($node);
|
|
601
624
|
}
|
|
602
625
|
}
|
|
603
626
|
|
|
604
627
|
// 阶段2:处理不活跃节点
|
|
628
|
+
// 【优化】用 Set 判断是否已在 nodePool 中,避免 indexOf O(n)
|
|
629
|
+
const nodePoolSet = new Set(this.nodePool);
|
|
605
630
|
this.activeNodes.forEach($node => {
|
|
606
631
|
$node.css('transform', `translateY(-9999px)`);// 移出可视区域
|
|
607
|
-
if (
|
|
632
|
+
if (!nodePoolSet.has($node)) {
|
|
608
633
|
this.nodePool.push($node);
|
|
634
|
+
nodePoolSet.add($node);
|
|
609
635
|
}
|
|
610
636
|
});
|
|
611
637
|
this.activeNodes = newActiveNodes;
|
|
@@ -797,7 +823,7 @@ Waterfallv2.prototype.createColumn = function (index) {
|
|
|
797
823
|
return res;
|
|
798
824
|
}
|
|
799
825
|
|
|
800
|
-
Waterfallv2.prototype.updateRenderUI = function ($node, data, dataId) {
|
|
826
|
+
Waterfallv2.prototype.updateRenderUI = function ($node, data, dataId, _originalIndex) {
|
|
801
827
|
const options = this.options;
|
|
802
828
|
|
|
803
829
|
if (!this.dataIdMap.has(dataId)) {
|
|
@@ -805,8 +831,8 @@ Waterfallv2.prototype.updateRenderUI = function ($node, data, dataId) {
|
|
|
805
831
|
return;
|
|
806
832
|
}
|
|
807
833
|
|
|
808
|
-
//
|
|
809
|
-
const originalIndex = options.data.indexOf(data);
|
|
834
|
+
// 【优化】如果调用方已传入索引则直接使用,避免 O(n) 的 indexOf 查找
|
|
835
|
+
const originalIndex = (_originalIndex !== undefined) ? _originalIndex : options.data.indexOf(data);
|
|
810
836
|
|
|
811
837
|
if (this.hasUpdateItem === true) {
|
|
812
838
|
options.updateItem($node, data, originalIndex);
|
|
@@ -1075,8 +1101,7 @@ Waterfallv2.prototype.getSpecialNodeDOM = function (dataId) {
|
|
|
1075
1101
|
Waterfallv2.prototype.getBatchCardNewHeights = async function (dataIds, newData) {
|
|
1076
1102
|
const options = this.options;
|
|
1077
1103
|
const $ = getEnv().$;
|
|
1078
|
-
const $
|
|
1079
|
-
const $viewport = $container.find('.Waterfallv2-list-viewport');
|
|
1104
|
+
const $viewport = this.$viewport;
|
|
1080
1105
|
|
|
1081
1106
|
const cardInfos = new Map();
|
|
1082
1107
|
|
|
@@ -1279,8 +1304,7 @@ Waterfallv2.prototype.getCardNewHeight = async function (dataId, data) {
|
|
|
1279
1304
|
return this.getCardOldHeight(dataId);
|
|
1280
1305
|
}
|
|
1281
1306
|
|
|
1282
|
-
const $
|
|
1283
|
-
const $viewport = $container.find('.Waterfallv2-list-viewport');
|
|
1307
|
+
const $viewport = this.$viewport;
|
|
1284
1308
|
|
|
1285
1309
|
let $node = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
1286
1310
|
let isBorrowed = false;
|
|
@@ -1580,7 +1604,6 @@ Waterfallv2.prototype.hideLoading = function (callback = null) {
|
|
|
1580
1604
|
// 设置滚动条列表的高度
|
|
1581
1605
|
Waterfallv2.prototype.setScrollHeight = function () {
|
|
1582
1606
|
const options = this.options;
|
|
1583
|
-
const $container = $(options.container);
|
|
1584
1607
|
let h = this.getMaxHeight();
|
|
1585
1608
|
if (this.isShowLoading === true) {
|
|
1586
1609
|
if (this.$loadingNode) {
|
|
@@ -1588,7 +1611,8 @@ Waterfallv2.prototype.setScrollHeight = function () {
|
|
|
1588
1611
|
}
|
|
1589
1612
|
}
|
|
1590
1613
|
h += options.marginBottom;
|
|
1591
|
-
|
|
1614
|
+
// 【优化】使用缓存的 DOM 引用,避免每次 find 查询
|
|
1615
|
+
this.$scrollWrapper.css('height', h + 'px');
|
|
1592
1616
|
}
|
|
1593
1617
|
|
|
1594
1618
|
/**
|
|
@@ -1691,21 +1715,29 @@ function getBottomByColumn(column) {
|
|
|
1691
1715
|
return child[child.length - 1].bottom;
|
|
1692
1716
|
}
|
|
1693
1717
|
|
|
1718
|
+
// 【优化】保留 hasNodeInActives 供非热路径使用(如 createCards),但增加提前退出
|
|
1694
1719
|
function hasNodeInActives(mapObj, $node) {
|
|
1695
|
-
|
|
1696
|
-
mapObj.forEach((item) => {
|
|
1720
|
+
for (const item of mapObj.values()) {
|
|
1697
1721
|
if (item === $node) {
|
|
1698
|
-
|
|
1722
|
+
return true;
|
|
1699
1723
|
}
|
|
1700
|
-
}
|
|
1701
|
-
return
|
|
1724
|
+
}
|
|
1725
|
+
return false;
|
|
1702
1726
|
}
|
|
1703
1727
|
|
|
1704
|
-
//
|
|
1705
|
-
|
|
1728
|
+
// 【优化】从节点池取得一个未被使用的节点
|
|
1729
|
+
// usedNodes 参数现在接受 Set(O(1) 查找),同时兼容 Map(降级为遍历)
|
|
1730
|
+
function getNodePoolPop(nodePool, usedNodes) {
|
|
1706
1731
|
for (let i = 0; i < nodePool.length; i++) {
|
|
1707
1732
|
const $node = nodePool[i];
|
|
1708
|
-
|
|
1733
|
+
// 如果是 Set,直接用 has;如果是 Map,降级遍历
|
|
1734
|
+
let isUsed = false;
|
|
1735
|
+
if (usedNodes instanceof Set) {
|
|
1736
|
+
isUsed = usedNodes.has($node);
|
|
1737
|
+
} else {
|
|
1738
|
+
isUsed = hasNodeInActives(usedNodes, $node);
|
|
1739
|
+
}
|
|
1740
|
+
if (!isUsed) {
|
|
1709
1741
|
nodePool.splice(i, 1);
|
|
1710
1742
|
return $node;
|
|
1711
1743
|
}
|