tencent.jquery.pix.component 1.0.89 → 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/banner/banner.js +67 -24
- package/components/waterfallv2/waterfallv2.js +104 -72
- package/package.json +1 -1
package/change.md
CHANGED
|
@@ -18,6 +18,7 @@ let $ = null;
|
|
|
18
18
|
* @param {function} [options.click] 点击轮播图时触发,第一个参数为触发元素的jq,第二个参数为 options.list 中对应的项,第三个参数为当前页码
|
|
19
19
|
* @param {function} [options.pageChanged] 翻页时触发,第一个参数为新生效页面元素的jq,第二个参数为 options.list 中对应的项,第三个参数为当前页码
|
|
20
20
|
* @param {function} [options.renderCallback] 自定义渲染回调,第一个参数为 options.list 中对应的项,第二个参数为当前页码,返回值为渲染后的元素
|
|
21
|
+
* @param {boolean} [options.singNoSwitch=false] 当只有单张图片时是否禁用切换功能(隐藏分页和切换),默认为 false 即单图也展示分页和切换
|
|
21
22
|
*/
|
|
22
23
|
export function Banner(options = {}) {
|
|
23
24
|
$ = getEnv().$;
|
|
@@ -27,6 +28,7 @@ export function Banner(options = {}) {
|
|
|
27
28
|
this.options.autoResize ??= true;
|
|
28
29
|
this.options.durationMs = Number(options.durationMs || 0) || 0;
|
|
29
30
|
this.options.dragThreshold = Number(options.dragThreshold || 0.2) || 0.2;
|
|
31
|
+
this.options.singNoSwitch ??= false;
|
|
30
32
|
this.index = Number(options.index || 0) || 0;
|
|
31
33
|
// 用于保存 options.list 中每一项对应的 imgObj(按 list 索引存储),避免依赖 jQuery 的 data 功能
|
|
32
34
|
this.imgObjMap = {};
|
|
@@ -57,6 +59,9 @@ Banner.prototype.fitWidth = function () {
|
|
|
57
59
|
* 跳转到上一页
|
|
58
60
|
*/
|
|
59
61
|
Banner.prototype.prevPage = async function () {
|
|
62
|
+
if (this.options.singNoSwitch && this.options.list.length <= 1) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
60
65
|
this.pauseAutoPlay();
|
|
61
66
|
await this.gotoPageUnchecked(this.index - 1);
|
|
62
67
|
this.startAutoPlay();
|
|
@@ -66,6 +71,9 @@ Banner.prototype.prevPage = async function () {
|
|
|
66
71
|
* 跳转到下一页
|
|
67
72
|
*/
|
|
68
73
|
Banner.prototype.nextPage = async function () {
|
|
74
|
+
if (this.options.singNoSwitch && this.options.list.length <= 1) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
69
77
|
this.pauseAutoPlay();
|
|
70
78
|
await this.gotoPageUnchecked(this.index + 1);
|
|
71
79
|
this.startAutoPlay();
|
|
@@ -149,6 +157,10 @@ Banner.prototype.init = function () {
|
|
|
149
157
|
}
|
|
150
158
|
|
|
151
159
|
Banner.prototype.startAutoPlay = function () {
|
|
160
|
+
// 单图且 singNoSwitch 为 true 时,不启动自动播放
|
|
161
|
+
if (this.options.singNoSwitch && this.options.list.length === 1) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
152
164
|
if (this.options.durationMs > 0 && this.timer == null) {
|
|
153
165
|
this.timer = setInterval(() => {
|
|
154
166
|
this.nextPage()
|
|
@@ -173,9 +185,12 @@ Banner.prototype.createHtml = function () {
|
|
|
173
185
|
$t.empty();
|
|
174
186
|
const signWidth = this.signWidth = $t.width()
|
|
175
187
|
|
|
176
|
-
|
|
188
|
+
// 单图且 singNoSwitch 为 true 时,不创建循环占位,直接展示单张图片
|
|
189
|
+
const isSingleNoSwitch = this.options.singNoSwitch && len === 1;
|
|
190
|
+
|
|
191
|
+
const allWidth = this.allWidth = isSingleNoSwitch ? signWidth : signWidth * (len + 2)
|
|
177
192
|
const $inner = this.$inner = $(`<div class="banner-inner-transform"></div>`)
|
|
178
|
-
this.currentTranslate = -signWidth * (this.index + 1)
|
|
193
|
+
this.currentTranslate = isSingleNoSwitch ? 0 : -signWidth * (this.index + 1)
|
|
179
194
|
$inner.width(allWidth).css('transform', `translateX(${this.currentTranslate}px)`)
|
|
180
195
|
|
|
181
196
|
// 重置 imgObj 映射表,按 list 的索引保存 imgObj 引用
|
|
@@ -186,10 +201,12 @@ Banner.prototype.createHtml = function () {
|
|
|
186
201
|
}
|
|
187
202
|
}
|
|
188
203
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
204
|
+
if (!isSingleNoSwitch) {
|
|
205
|
+
// 加第0个位置
|
|
206
|
+
$inner.append(`<div class="banner-inner-li" data-background-url="${this.options.list[len - 1].url}" style="width:${this.signWidth}px;">
|
|
207
|
+
</div>
|
|
208
|
+
`)
|
|
209
|
+
}
|
|
193
210
|
for (let i = 0; i < len; i++) {
|
|
194
211
|
const item = this.options.list[i]
|
|
195
212
|
const $li = $(`<div class="banner-inner-li" data-background-url="${item.url}" style="width:${this.signWidth}px;">
|
|
@@ -197,19 +214,23 @@ Banner.prototype.createHtml = function () {
|
|
|
197
214
|
`)
|
|
198
215
|
$inner.append($li)
|
|
199
216
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
217
|
+
if (!isSingleNoSwitch) {
|
|
218
|
+
// 加第N+1
|
|
219
|
+
$inner.append(`<div class="banner-inner-li" data-background-url="${this.options.list[0].url}" style="width:${this.signWidth}px;">
|
|
220
|
+
</div>
|
|
221
|
+
`)
|
|
222
|
+
}
|
|
204
223
|
|
|
205
224
|
const preloadIdx = this.index;
|
|
206
225
|
this.loadBackground(preloadIdx);
|
|
207
|
-
|
|
208
|
-
|
|
226
|
+
if (!isSingleNoSwitch) {
|
|
227
|
+
this.loadBackground((preloadIdx + 1) % len); // prev
|
|
228
|
+
this.loadBackground((preloadIdx - 1 + len) % len); // next
|
|
229
|
+
}
|
|
209
230
|
|
|
210
231
|
$t.append($inner)
|
|
211
232
|
|
|
212
|
-
if (this.options.isTitleEnabled) {
|
|
233
|
+
if (this.options.isTitleEnabled && !isSingleNoSwitch) {
|
|
213
234
|
// 创建 titlebox
|
|
214
235
|
const $titleBox = $(`<div class="banner-title-box">${this.options.list[this.index].title}</div>`)
|
|
215
236
|
|
|
@@ -246,24 +267,31 @@ Banner.prototype.createCustomHtml = function () {
|
|
|
246
267
|
$t.empty();
|
|
247
268
|
const signWidth = this.signWidth = $t.width()
|
|
248
269
|
|
|
249
|
-
|
|
270
|
+
// 单图且 singNoSwitch 为 true 时,不创建循环占位
|
|
271
|
+
const isSingleNoSwitch = this.options.singNoSwitch && len === 1;
|
|
272
|
+
|
|
273
|
+
const allWidth = this.allWidth = isSingleNoSwitch ? signWidth : signWidth * (len + 2)
|
|
250
274
|
const $inner = this.$inner = $(`<div class="banner-inner-transform"></div>`)
|
|
251
|
-
this.currentTranslate = -signWidth * (this.index + 1)
|
|
275
|
+
this.currentTranslate = isSingleNoSwitch ? 0 : -signWidth * (this.index + 1)
|
|
252
276
|
$inner.width(allWidth).css('transform', `translateX(${this.currentTranslate}px)`)
|
|
253
277
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
278
|
+
if (!isSingleNoSwitch) {
|
|
279
|
+
let $li = $(this.options.renderCallback(this.options.list[len - 1], len - 1));
|
|
280
|
+
$li.width(signWidth);
|
|
281
|
+
$inner.append($li);
|
|
282
|
+
}
|
|
257
283
|
|
|
258
284
|
for (let i = 0; i < len; i++) {
|
|
259
|
-
$li = $(this.options.renderCallback(this.options.list[i], i));
|
|
285
|
+
let $li = $(this.options.renderCallback(this.options.list[i], i));
|
|
260
286
|
$li.width(signWidth);
|
|
261
287
|
$inner.append($li);
|
|
262
288
|
}
|
|
263
289
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
290
|
+
if (!isSingleNoSwitch) {
|
|
291
|
+
let $li = $(this.options.renderCallback(this.options.list[0], 0));
|
|
292
|
+
$li.width(signWidth);
|
|
293
|
+
$inner.append($li);
|
|
294
|
+
}
|
|
267
295
|
|
|
268
296
|
$t.append($inner);
|
|
269
297
|
}
|
|
@@ -273,6 +301,19 @@ Banner.prototype.bindEvent = function () {
|
|
|
273
301
|
const len = this.options.list.length;
|
|
274
302
|
const $inner = this.$inner;
|
|
275
303
|
|
|
304
|
+
// 单图且 singNoSwitch 为 true 时,不绑定拖拽和切换事件
|
|
305
|
+
if (this.options.singNoSwitch && len === 1) {
|
|
306
|
+
// 仅绑定点击事件
|
|
307
|
+
$inner.on('click', function (e) {
|
|
308
|
+
if (!self.options.click) {
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
const $t = self.$inner.children().eq(0);
|
|
312
|
+
self.options.click($t, self.options.list[0], 0);
|
|
313
|
+
});
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
276
317
|
// pStart 时的 clientX
|
|
277
318
|
let originalX = 0;
|
|
278
319
|
|
|
@@ -467,8 +508,9 @@ function childIdxToListIdx(childIdx, len) {
|
|
|
467
508
|
Banner.prototype.loadAllBackgrounds = function () {
|
|
468
509
|
const len = this.options.list.length;
|
|
469
510
|
const imgObjMap = this.imgObjMap || {};
|
|
511
|
+
const isSingleNoSwitch = this.options.singNoSwitch && len === 1;
|
|
470
512
|
this.$inner.children().each(function (childIdx) {
|
|
471
|
-
const listIdx = childIdxToListIdx(childIdx, len);
|
|
513
|
+
const listIdx = isSingleNoSwitch ? childIdx : childIdxToListIdx(childIdx, len);
|
|
472
514
|
applyBackgroundImage($(this), imgObjMap[listIdx]);
|
|
473
515
|
});
|
|
474
516
|
// console.log('banner images loaded');
|
|
@@ -481,7 +523,8 @@ Banner.prototype.loadAllBackgrounds = function () {
|
|
|
481
523
|
Banner.prototype.loadBackground = function (pos) {
|
|
482
524
|
console.log('loadBackground pos === ', pos);
|
|
483
525
|
const imgObjMap = this.imgObjMap || {};
|
|
484
|
-
|
|
526
|
+
const isSingleNoSwitch = this.options.singNoSwitch && this.options.list.length === 1;
|
|
527
|
+
let $item = this.$inner.children().eq(isSingleNoSwitch ? pos : pos + 1);
|
|
485
528
|
applyBackgroundImage($item, imgObjMap[pos]);
|
|
486
529
|
|
|
487
530
|
// 加载滚动占位的图片
|
|
@@ -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
|
}
|