tencent.jquery.pix.component 1.0.62 → 1.0.63-beta.2
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 +337 -74
- package/package.json +1 -1
|
@@ -19,10 +19,11 @@ const DEFAULTS = {
|
|
|
19
19
|
// 传入 $node, data, index
|
|
20
20
|
updateItem: null, // 元素更新时的回调函数
|
|
21
21
|
onscroll: null, // 滚动事件回调函数
|
|
22
|
+
shouldOccupySpace: null // 是否是静态数据的回调函数,静态数据能够占用元素
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
export function Waterfall(optionsInput = {}) {
|
|
25
|
-
$ = getEnv()
|
|
26
|
+
$ = getEnv().$;
|
|
26
27
|
|
|
27
28
|
this.options = Object.assign({}, DEFAULTS, optionsInput);
|
|
28
29
|
const options = this.options;
|
|
@@ -30,6 +31,12 @@ export function Waterfall(optionsInput = {}) {
|
|
|
30
31
|
// 标记是否有更新元素用的回调函数
|
|
31
32
|
this.hasUpdateItem = options.updateItem && (options.updateItem.constructor === Function) ? true : false;
|
|
32
33
|
|
|
34
|
+
// 新方案:数据ID映射机制
|
|
35
|
+
this.dataIdMap = new Map(); // 数据ID -> 布局信息映射
|
|
36
|
+
this.nextDataId = 0; // 下一个数据ID
|
|
37
|
+
this.renderedDataIds = new Set(); // 已渲染的数据ID集合
|
|
38
|
+
|
|
39
|
+
|
|
33
40
|
// 间隔字符串转数字
|
|
34
41
|
if (options.columnGap.constructor === String) {
|
|
35
42
|
// 如果是rem单位,则需要计算
|
|
@@ -85,13 +92,29 @@ export function Waterfall(optionsInput = {}) {
|
|
|
85
92
|
this.columnItems.push(this.createColumn(i));
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
this.renderIndex = 0; //
|
|
89
|
-
this.activeNodes = new Map(); //
|
|
95
|
+
this.renderIndex = 0; // 渲染索引(保留兼容性)
|
|
96
|
+
this.activeNodes = new Map(); // 当前活跃节点(数据ID -> DOM)
|
|
90
97
|
this.nodePool = []; // DOM 节点池
|
|
91
98
|
|
|
99
|
+
// 新方案:初始化数据ID映射
|
|
100
|
+
this.dataIdMap = new Map(); // 数据ID -> 布局信息映射
|
|
101
|
+
this.nextDataId = 0; // 下一个数据ID
|
|
102
|
+
this.renderedDataIds = new Set(); // 已渲染的数据ID集合
|
|
103
|
+
|
|
104
|
+
// 为初始数据分配数据ID
|
|
105
|
+
this.options.data.forEach((item, index) => {
|
|
106
|
+
const dataId = index; //this.nextDataId++;
|
|
107
|
+
this.dataIdMap.set(dataId, {
|
|
108
|
+
data: true,//item,
|
|
109
|
+
originalIndex: index,
|
|
110
|
+
layoutInfo: null // 将在布局时填充
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
92
114
|
this.init();
|
|
93
115
|
}
|
|
94
116
|
|
|
117
|
+
|
|
95
118
|
Waterfall.prototype.init = function () {
|
|
96
119
|
const self = this;
|
|
97
120
|
const options = this.options;
|
|
@@ -99,6 +122,8 @@ Waterfall.prototype.init = function () {
|
|
|
99
122
|
|
|
100
123
|
this.nodePool = []; // DOM 节点池
|
|
101
124
|
this.activeNodes = new Map(); // 当前活跃节点(索引 -> DOM)
|
|
125
|
+
this.allReadyNodes = new Map(); // 所有节点(索引 -> DOM)
|
|
126
|
+
this.renderIndex = 0; // 渲染索引(保留兼容性)
|
|
102
127
|
|
|
103
128
|
|
|
104
129
|
|
|
@@ -134,8 +159,9 @@ Waterfall.prototype.updateVisibleItems = function (force = false) {
|
|
|
134
159
|
const options = this.options;
|
|
135
160
|
const $container = $(options.container);
|
|
136
161
|
|
|
137
|
-
const startTop =
|
|
162
|
+
const startTop = self.scrollTop; // 当前滚动位置
|
|
138
163
|
const endTop = startTop + $container.height();
|
|
164
|
+
// console.log('startTop', startTop)
|
|
139
165
|
|
|
140
166
|
// 进行可见区域的渲染更新
|
|
141
167
|
this.updateCardsInView({
|
|
@@ -143,23 +169,47 @@ Waterfall.prototype.updateVisibleItems = function (force = false) {
|
|
|
143
169
|
end: endTop,
|
|
144
170
|
force
|
|
145
171
|
});
|
|
172
|
+
|
|
146
173
|
}
|
|
147
174
|
|
|
148
175
|
// 新增卡片
|
|
149
|
-
Waterfall.prototype.appendCard = function (data,
|
|
176
|
+
Waterfall.prototype.appendCard = function (data, dataId, { top, left }) {
|
|
177
|
+
if (this.renderedDataIds.has(dataId)) {
|
|
178
|
+
return
|
|
179
|
+
}
|
|
150
180
|
const self = this;
|
|
151
181
|
const options = this.options;
|
|
152
182
|
const $container = $(options.container);
|
|
153
183
|
const $viewport = $container.find('.waterfall-list-viewport');
|
|
184
|
+
|
|
185
|
+
// 新方案:基于数据ID的数据验证
|
|
186
|
+
if (!this.dataIdMap.has(dataId)) {
|
|
187
|
+
console.error('Waterfall: Invalid dataId in appendCard', dataId);
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const dataInfo = this.dataIdMap.get(dataId);
|
|
192
|
+
if (!dataInfo || !dataInfo.data) {
|
|
193
|
+
console.warn('Waterfall: Empty data for dataId', dataId);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
154
197
|
const $card = $(
|
|
155
198
|
`<div class="waterfall-item"
|
|
156
|
-
data-index="${
|
|
157
|
-
style="position: absolute;transform:translate(${left}px,${top}px);
|
|
199
|
+
data-index="${dataId}"
|
|
200
|
+
style="position: absolute;transform:translate(${left}px,${top}px);"
|
|
158
201
|
>
|
|
159
|
-
${options.renderItem(data,
|
|
202
|
+
${options.renderItem(data, dataInfo.originalIndex)}
|
|
160
203
|
</div> `
|
|
161
204
|
);
|
|
162
205
|
|
|
206
|
+
this.renderedDataIds.add(dataId);
|
|
207
|
+
|
|
208
|
+
if (options.columns !== 1) {
|
|
209
|
+
$card.width(this.columnWidth + 'px');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
|
|
163
213
|
$viewport.append($card);
|
|
164
214
|
return $card;
|
|
165
215
|
}
|
|
@@ -174,49 +224,105 @@ Waterfall.prototype.updateCardsInView = function ({ start, end, force = false })
|
|
|
174
224
|
this.createCards({ end: endBuffer });
|
|
175
225
|
}
|
|
176
226
|
|
|
177
|
-
|
|
178
|
-
|
|
227
|
+
const startNum = start - options.bufferHeight;
|
|
228
|
+
const endNum = end + options.bufferHeight;
|
|
229
|
+
// 新方案:基于数据ID映射机制
|
|
179
230
|
const newActiveNodes = new Map();
|
|
180
231
|
for (let i = 0; i < this.columns; i++) {
|
|
181
232
|
const column = this.columnItems[i];
|
|
182
233
|
|
|
183
234
|
for (let j = 0; j < column.children.length; j++) {
|
|
184
235
|
const row = column.children[j];
|
|
185
|
-
const
|
|
236
|
+
const dataId = row.dataId; // 使用dataId替代renderIndex
|
|
237
|
+
|
|
238
|
+
// 验证数据ID有效性
|
|
239
|
+
if (!this.dataIdMap.has(dataId)) {
|
|
240
|
+
console.warn('Waterfall: Invalid dataId detected', dataId);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const dataInfo = this.dataIdMap.get(dataId);
|
|
245
|
+
|
|
246
|
+
if (!dataInfo) {
|
|
247
|
+
console.warn('Waterfall: Invalid data for dataId', dataId);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const data = options.data[dataId]
|
|
252
|
+
|
|
253
|
+
// 如果当前这个节点是特殊节点 不用做处理
|
|
254
|
+
// 如果是特殊的静态占用元素卡片,需要指定节点不变更的数据,那么该数据的节点不能被其他数据使用
|
|
255
|
+
let specialNode = false;
|
|
256
|
+
if (options.shouldOccupySpace) {
|
|
257
|
+
specialNode = options.shouldOccupySpace(data) || false;
|
|
258
|
+
}
|
|
259
|
+
if (specialNode) {
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
186
263
|
// 在可视区域内 进行有关卡片的操作
|
|
187
|
-
|
|
264
|
+
const bool = row.top <= endNum && row.bottom >= startNum;
|
|
265
|
+
if (bool) {
|
|
188
266
|
// 理论上什么都不动,因为卡片的位置不会变
|
|
189
|
-
const $card = this.activeNodes.get(
|
|
267
|
+
const $card = this.activeNodes.get(dataId);
|
|
190
268
|
|
|
191
269
|
let $node = null;
|
|
192
|
-
|
|
270
|
+
|
|
271
|
+
// 遍历当前的节点是否被占用,如果被占用的话,就得要从nodePool中取一个
|
|
272
|
+
let bool = true;
|
|
193
273
|
if ($card) {
|
|
274
|
+
bool = hasNodeInActives(newActiveNodes, $card)
|
|
275
|
+
}
|
|
276
|
+
// 如果卡片已经在DOM中,则不用更新位置
|
|
277
|
+
if (bool === false) {
|
|
194
278
|
$node = $card;
|
|
195
|
-
this.activeNodes.delete(
|
|
279
|
+
this.activeNodes.delete(dataId);
|
|
280
|
+
// 如果是强更,这里才会采取更新
|
|
196
281
|
if (force) {
|
|
197
|
-
this.updateRenderUI($node,
|
|
282
|
+
this.updateRenderUI($node, data, dataId);
|
|
198
283
|
}
|
|
284
|
+
|
|
199
285
|
} else {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
286
|
+
const $card = this.allReadyNodes.get(dataId);
|
|
287
|
+
// 遍历当前的节点是否被占用,如果被占用的话,就得要从nodePool中取一个
|
|
288
|
+
let bool = true;
|
|
289
|
+
if ($card) {
|
|
290
|
+
bool = hasNodeInActives(newActiveNodes, $card)
|
|
291
|
+
}
|
|
292
|
+
if (bool === false) {
|
|
293
|
+
// 如果成功获取到card并没有占用 那么就复用这个card
|
|
294
|
+
$node = $card;
|
|
295
|
+
|
|
296
|
+
this.updateRenderUI($node, data, dataId);
|
|
297
|
+
|
|
209
298
|
} else {
|
|
210
|
-
|
|
211
|
-
$node.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
299
|
+
// 卡片不在DOM中,则更新位置
|
|
300
|
+
$node = getNodePoolPop(this.nodePool, newActiveNodes);
|
|
301
|
+
if ($node === null) {
|
|
302
|
+
// 这里是往上方拖动时,可能需要补建的情况
|
|
303
|
+
$node = this.appendCard(data, dataId, {
|
|
304
|
+
top: row.top, left: row.left
|
|
305
|
+
});
|
|
306
|
+
row.$node = $node;
|
|
307
|
+
} else {
|
|
308
|
+
this.updateRenderUI($node, data, dataId);
|
|
309
|
+
row.$node = $node;
|
|
310
|
+
}
|
|
216
311
|
}
|
|
217
312
|
}
|
|
313
|
+
$node.css({
|
|
314
|
+
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
315
|
+
}).attr('data-index', dataId);
|
|
218
316
|
|
|
219
|
-
newActiveNodes.set(
|
|
317
|
+
newActiveNodes.set(dataId, $node);
|
|
318
|
+
|
|
319
|
+
// 清除掉在NodePool中的card
|
|
320
|
+
const index = this.nodePool.indexOf($card);
|
|
321
|
+
if (index !== -1) {
|
|
322
|
+
this.nodePool.splice(index, 1);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// console.log('302-row', row.dataId, dataInfo);
|
|
220
326
|
}
|
|
221
327
|
}
|
|
222
328
|
}
|
|
@@ -224,11 +330,16 @@ Waterfall.prototype.updateCardsInView = function ({ start, end, force = false })
|
|
|
224
330
|
// 阶段2:处理不活跃节点
|
|
225
331
|
this.activeNodes.forEach($node => {
|
|
226
332
|
$node.css('transform', `translateY(-9999px)`);// 移出可视区域
|
|
227
|
-
this.nodePool.
|
|
333
|
+
if (this.nodePool.indexOf($node) === -1) {
|
|
334
|
+
this.nodePool.push($node);
|
|
335
|
+
}
|
|
228
336
|
});
|
|
229
337
|
this.activeNodes = newActiveNodes;
|
|
338
|
+
// console.log('this.activeNodes', this.activeNodes);
|
|
339
|
+
// console.log('this.nodePool', this.nodePool);
|
|
230
340
|
}
|
|
231
341
|
|
|
342
|
+
|
|
232
343
|
Waterfall.prototype.getMaxHeight = function () {
|
|
233
344
|
let maxHeight = 0;
|
|
234
345
|
for (let i = 0; i < this.columns; i++) {
|
|
@@ -276,79 +387,127 @@ Waterfall.prototype.getMinHeightColumn = function () {
|
|
|
276
387
|
}
|
|
277
388
|
|
|
278
389
|
// 创建卡片
|
|
279
|
-
Waterfall.prototype.createCards = function ({ end }) {
|
|
390
|
+
Waterfall.prototype.createCards = function ({ end, dataId = -1 }) {
|
|
280
391
|
const self = this;
|
|
281
392
|
const options = this.options;
|
|
282
393
|
const $container = $(options.container);
|
|
283
|
-
const renderIndex = this.renderIndex;
|
|
284
394
|
|
|
285
|
-
|
|
395
|
+
// 新方案:获取下一个未渲染的数据ID
|
|
396
|
+
let nextDataId = null;
|
|
397
|
+
for (let [dataId, dataInfo] of this.dataIdMap) {
|
|
398
|
+
if (!this.renderedDataIds.has(dataId)) {
|
|
399
|
+
nextDataId = dataId;
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
// 如果没有更多数据需要渲染
|
|
406
|
+
if (nextDataId === null) {
|
|
286
407
|
const maxHeight = this.getMaxHeight();
|
|
287
|
-
|
|
288
|
-
$(options.container).find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom)
|
|
408
|
+
$container.find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
289
409
|
return;
|
|
290
410
|
}
|
|
291
411
|
|
|
412
|
+
const dataInfo = this.dataIdMap.get(nextDataId);
|
|
413
|
+
if (!dataInfo || !dataInfo.data) {
|
|
414
|
+
console.warn('Waterfall: Invalid data for dataId', nextDataId);
|
|
415
|
+
this.renderedDataIds.add(nextDataId);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (this.renderIndex >= options.data.length) {
|
|
420
|
+
const maxHeight = this.getMaxHeight();
|
|
421
|
+
$container.find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
422
|
+
return
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const data = options.data[nextDataId];
|
|
426
|
+
|
|
292
427
|
let column = this.getMinHeightColumn();
|
|
293
428
|
if (column === null) {
|
|
294
|
-
// 没有可用的列,则在第一列创建,说明此时还没有数据
|
|
295
429
|
column = this.columnItems[0];
|
|
296
430
|
}
|
|
297
431
|
|
|
298
432
|
const top = column.bottom === 0 ? options.marginTop : (column.bottom + options.rowGap);
|
|
433
|
+
const position = { top, left: column.left };
|
|
434
|
+
const row = createDefaultRow(position);
|
|
299
435
|
|
|
300
|
-
|
|
301
|
-
const position = {
|
|
302
|
-
top,
|
|
303
|
-
left: column.left,
|
|
304
|
-
}
|
|
436
|
+
this.renderIndex += 1;
|
|
305
437
|
|
|
306
|
-
|
|
438
|
+
let specialNode = false;
|
|
307
439
|
|
|
440
|
+
// 如果是特殊的卡片,需要指定节点不变更的数据,那么该数据的节点不能被其他数据使用
|
|
441
|
+
if (options.shouldOccupySpace) {
|
|
442
|
+
specialNode = options.shouldOccupySpace(data) || false;
|
|
443
|
+
}
|
|
308
444
|
|
|
309
|
-
//
|
|
445
|
+
// 添加卡片,使用dataId作为唯一标识
|
|
310
446
|
let $card = null;
|
|
311
|
-
if (this.nodePool.length === 0) {
|
|
312
|
-
$card = this.appendCard(
|
|
447
|
+
if (this.nodePool.length === 0 || specialNode === true) {
|
|
448
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
313
449
|
} else {
|
|
314
|
-
$
|
|
315
|
-
$
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
450
|
+
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
451
|
+
if ($tmp) {
|
|
452
|
+
$card = $tmp;
|
|
453
|
+
$card.css({
|
|
454
|
+
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
455
|
+
}).attr('data-index', nextDataId);
|
|
456
|
+
this.updateRenderUI($card, data, nextDataId);
|
|
457
|
+
} else {
|
|
458
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
459
|
+
}
|
|
320
460
|
|
|
461
|
+
}
|
|
321
462
|
|
|
322
463
|
row.$node = $card;
|
|
464
|
+
row.dataId = nextDataId; // 使用dataId替代renderIndex
|
|
465
|
+
if (dataId !== -1) {
|
|
466
|
+
row.dataId = dataId;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// 记录布局信息
|
|
470
|
+
// dataInfo.layoutInfo = {
|
|
471
|
+
// //columnIndex: this.columnItems.indexOf(column),
|
|
472
|
+
// //position: position,
|
|
473
|
+
// // row: row
|
|
474
|
+
// };
|
|
475
|
+
|
|
323
476
|
|
|
324
|
-
// 把新增的卡片放进 activeNodes, 当前是 展示状态的
|
|
325
|
-
this.activeNodes.set(renderIndex, $card);
|
|
326
477
|
|
|
327
478
|
|
|
479
|
+
if (specialNode === false) {
|
|
480
|
+
// 把新增的卡片放进 activeNodes 当成活跃节点元素,那么是 可以动态使用的
|
|
481
|
+
this.activeNodes.set(nextDataId, $card);
|
|
482
|
+
|
|
483
|
+
this.allReadyNodes.set(nextDataId, $card);
|
|
484
|
+
} else {
|
|
485
|
+
// 如果是特殊的,这里不要记录了
|
|
486
|
+
this.allReadyNodes.set(nextDataId, null);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
this.renderedDataIds.add(nextDataId);
|
|
490
|
+
|
|
328
491
|
// 更新列的底部距离
|
|
329
492
|
column.bottom = top + $card.height();
|
|
330
493
|
column.children.push(row);
|
|
331
|
-
|
|
332
|
-
// 计算当前卡片的位置
|
|
333
494
|
row.bottom = column.bottom;
|
|
334
|
-
row.renderIndex = renderIndex;
|
|
335
|
-
|
|
336
|
-
this.renderIndex += 1;
|
|
337
|
-
|
|
338
|
-
let hasNextData = this.renderIndex < options.data.length;
|
|
339
495
|
|
|
496
|
+
// 检查是否需要继续创建卡片
|
|
340
497
|
const minHeight = this.getMinHeight();
|
|
341
|
-
|
|
498
|
+
const hasMoreData = this.renderedDataIds.size < this.dataIdMap.size;
|
|
499
|
+
|
|
500
|
+
if (hasMoreData && (minHeight < end)) {
|
|
342
501
|
window.requestAnimationFrame(() => {
|
|
343
502
|
this.createCards({ end });
|
|
344
503
|
});
|
|
345
504
|
} else {
|
|
346
505
|
const maxHeight = this.getMaxHeight();
|
|
347
|
-
|
|
348
|
-
$(options.container).find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom)
|
|
506
|
+
$(options.container).find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
349
507
|
}
|
|
350
508
|
}
|
|
351
509
|
|
|
510
|
+
|
|
352
511
|
Waterfall.prototype.createColumn = function (index) {
|
|
353
512
|
const res = {
|
|
354
513
|
left: 0,
|
|
@@ -365,33 +524,137 @@ Waterfall.prototype.createColumn = function (index) {
|
|
|
365
524
|
return res;
|
|
366
525
|
}
|
|
367
526
|
|
|
368
|
-
Waterfall.prototype.updateRenderUI = function ($node, data,
|
|
527
|
+
Waterfall.prototype.updateRenderUI = function ($node, data, dataId) {
|
|
369
528
|
const options = this.options;
|
|
529
|
+
|
|
530
|
+
// 新方案:基于数据ID的数据验证
|
|
531
|
+
if (!this.dataIdMap.has(dataId)) {
|
|
532
|
+
console.error('Waterfall: Invalid dataId in updateRenderUI', dataId);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const dataInfo = this.dataIdMap.get(dataId);
|
|
537
|
+
if (!dataInfo || !dataInfo.data) {
|
|
538
|
+
console.warn('Waterfall: Empty data for dataId', dataId);
|
|
539
|
+
}
|
|
540
|
+
|
|
370
541
|
if (this.hasUpdateItem === true) {
|
|
371
|
-
options.updateItem($node, data,
|
|
542
|
+
options.updateItem($node, data, dataInfo.originalIndex)
|
|
372
543
|
} else {
|
|
373
|
-
$node.html(options.renderItem(data,
|
|
544
|
+
$node.html(options.renderItem(data, dataInfo.originalIndex));
|
|
374
545
|
}
|
|
375
546
|
}
|
|
376
547
|
|
|
548
|
+
|
|
549
|
+
|
|
377
550
|
Waterfall.prototype.updateData = function (newData) {
|
|
378
|
-
|
|
551
|
+
const options = this.options;
|
|
552
|
+
options.data = newData;
|
|
553
|
+
|
|
554
|
+
// 新方案:重新建立数据ID映射
|
|
555
|
+
//this.dataIdMap.clear();
|
|
556
|
+
//this.renderedDataIds.clear();
|
|
557
|
+
//this.nextDataId = 0;
|
|
558
|
+
|
|
559
|
+
// 为每个数据项分配唯一ID
|
|
560
|
+
options.data.forEach((item, index) => {
|
|
561
|
+
const dataId = index; // this.nextDataId++;
|
|
562
|
+
if (!this.allReadyNodes.has(dataId)) {
|
|
563
|
+
this.dataIdMap.set(dataId, {
|
|
564
|
+
data: true,// item,
|
|
565
|
+
originalIndex: index,
|
|
566
|
+
layoutInfo: null // 将在布局时填充
|
|
567
|
+
});
|
|
568
|
+
// 如果没有准备好这个数据,这里要创建一个占位节点
|
|
569
|
+
this.createCards({ end: 0, dataId });
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
379
573
|
this.updateVisibleItems(true); // 强制更新渲染
|
|
574
|
+
|
|
575
|
+
// 重新计算所有卡片位置并更新位置
|
|
576
|
+
// this.updatePointCards();
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
// 重新计算设置一遍所有的卡片位置
|
|
582
|
+
Waterfall.prototype.updatePointCards = function () {
|
|
583
|
+
// 有问题 不要用
|
|
584
|
+
return
|
|
585
|
+
const self = this;
|
|
586
|
+
const options = this.options;
|
|
587
|
+
const columnItems = this.columnItems;
|
|
588
|
+
let top = options.marginTop;
|
|
589
|
+
for (let i = 0; i < columnItems.length; i++) {
|
|
590
|
+
const column = columnItems[i];
|
|
591
|
+
// 这里为了简化,各列的瀑布流保持不动,只更新各列下节点的top位置,不做节点的跨列位移
|
|
592
|
+
for (let j = 0; j < column.children.length; j++) {
|
|
593
|
+
const row = column.children[j];
|
|
594
|
+
const $card = row.$node;
|
|
595
|
+
|
|
596
|
+
// 验证数据ID有效性
|
|
597
|
+
if (!this.dataIdMap.has(row.dataId)) {
|
|
598
|
+
console.warn('Waterfall: Invalid dataId in updatePointCards', row.dataId);
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// 第一个的top不需要更新
|
|
603
|
+
if (j === 0) {
|
|
604
|
+
row.bottom = top + $card.height();
|
|
605
|
+
} else {
|
|
606
|
+
row.top = column.children[j - 1].bottom + options.rowGap;
|
|
607
|
+
row.bottom = row.top + $card.height();
|
|
608
|
+
// 更新卡片位置
|
|
609
|
+
// $card.css({
|
|
610
|
+
// 'transform': `translate(${row.left}px,${row.top}px)`,
|
|
611
|
+
// })
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
// 设置一次该列的bottom
|
|
616
|
+
column.bottom = getBottomByColumn(column);
|
|
617
|
+
}
|
|
380
618
|
}
|
|
381
619
|
|
|
620
|
+
|
|
382
621
|
function createDefaultRow({ top, left }) {
|
|
383
622
|
return {
|
|
384
623
|
top,
|
|
385
624
|
left,
|
|
386
625
|
bottom: 0,
|
|
387
626
|
$node: null,
|
|
388
|
-
|
|
627
|
+
dataId: -1 // 新方案:使用dataId替代renderIndex
|
|
389
628
|
}
|
|
390
629
|
}
|
|
391
630
|
|
|
392
|
-
|
|
393
|
-
|
|
631
|
+
|
|
632
|
+
function getBottomByColumn(column) {
|
|
633
|
+
if (column.children.length === 0) {
|
|
394
634
|
return 0;
|
|
395
635
|
}
|
|
396
|
-
|
|
636
|
+
const child = column.children;
|
|
637
|
+
return child[child.length - 1].bottom;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function hasNodeInActives(mapObj, $node) {
|
|
641
|
+
let bool = false
|
|
642
|
+
mapObj.forEach((item) => {
|
|
643
|
+
if (item === $node) {
|
|
644
|
+
bool = true;
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
return bool;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// 从众多jq对象数组取得一个不重复的
|
|
651
|
+
function getNodePoolPop(nodePool, actives) {
|
|
652
|
+
for (let i = 0; i < nodePool.length; i++) {
|
|
653
|
+
const $node = nodePool[i];
|
|
654
|
+
if (!hasNodeInActives(actives, $node)) {
|
|
655
|
+
nodePool.splice(i, 1);
|
|
656
|
+
return $node;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return null;
|
|
397
660
|
}
|