tencent.jquery.pix.component 1.0.66 → 1.0.67
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/video/videoplayer.js +141 -21
- package/components/waterfall/waterfall.js +172 -125
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ import './videocss.scss'
|
|
|
13
13
|
* @param {object} options 选项
|
|
14
14
|
* @param {string} options.container 容器元素的jquery选择器
|
|
15
15
|
* @param {string} options.vid 腾讯视频id
|
|
16
|
+
* @param {string} [options.videoUrl] 视频地址,非腾讯视频时使用,比如上传到cos的视频
|
|
16
17
|
* @param {string} [options.previewUrl] 视频预览图
|
|
17
18
|
* @param {0|1} [options.videoType=1] 视频类型选项,0: 标清,1: 高清
|
|
18
19
|
* @param {number} [options.autoHideControlsDelayMs=5000] 自动隐藏控制条延迟时间,单位ms
|
|
@@ -51,8 +52,14 @@ VideoPlayer.prototype.init = async function() {
|
|
|
51
52
|
clickToPause: false,
|
|
52
53
|
...this.options
|
|
53
54
|
}
|
|
55
|
+
//如果vid不存在,则直接获取option.videoUrl
|
|
56
|
+
const videoURL = this.options.vid ? await getVideoURL(this.options.vid, this.options.videoType) : this.options.videoUrl;
|
|
57
|
+
//如果videoUrl不存在,则抛出错误
|
|
58
|
+
if (!videoURL) {
|
|
54
59
|
|
|
55
|
-
|
|
60
|
+
throw new Error('videoURL is required');
|
|
61
|
+
|
|
62
|
+
}
|
|
56
63
|
$container.find('.myplayer-video-mask').before(`<video src="${videoURL}"></video>`);
|
|
57
64
|
|
|
58
65
|
this.state = {
|
|
@@ -61,6 +68,9 @@ VideoPlayer.prototype.init = async function() {
|
|
|
61
68
|
updatingProgress: false,
|
|
62
69
|
controlsDelayStart: 0,
|
|
63
70
|
firstPlay: true,
|
|
71
|
+
isFullScreen: false,
|
|
72
|
+
originalParent: null, // 保存原始父容器引用
|
|
73
|
+
originalNextSibling: null, // 保存原始位置的下一个兄弟节点
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
// 根据showProgressBar选项控制进度条显示
|
|
@@ -95,15 +105,27 @@ VideoPlayer.prototype.bindEvent = function() {
|
|
|
95
105
|
.on('canplay', 'video', () => {
|
|
96
106
|
console.log('canplay');
|
|
97
107
|
this.updateTotalTime();
|
|
108
|
+
})
|
|
109
|
+
.on('loadedmetadata', 'video', () => {
|
|
110
|
+
console.log('loadedmetadata');
|
|
111
|
+
this.updateTotalTime();
|
|
112
|
+
})
|
|
113
|
+
.on('durationchange', 'video', () => {
|
|
114
|
+
console.log('durationchange');
|
|
115
|
+
this.updateTotalTime();
|
|
116
|
+
})
|
|
117
|
+
.on('ended', 'video', () => {
|
|
118
|
+
console.log('video ended');
|
|
119
|
+
this.stop();
|
|
98
120
|
});
|
|
99
121
|
|
|
100
122
|
// 只有在显示进度条时才绑定进度条相关事件
|
|
101
123
|
if (this.options.showProgressBar) {
|
|
102
124
|
container
|
|
103
|
-
.on('dragstart', () => { console.log('video container dragstart') }
|
|
104
|
-
.on('drag', () => { console.log('video container drag') }
|
|
105
|
-
.on('dragend', () => { console.log('video container dragend') }
|
|
106
|
-
.on('click', () => { console.log('video container click') }
|
|
125
|
+
.on('dragstart', () => { console.log('video container dragstart') })
|
|
126
|
+
.on('drag', () => { console.log('video container drag') })
|
|
127
|
+
.on('dragend', () => { console.log('video container dragend') })
|
|
128
|
+
.on('click', () => { console.log('video container click') })
|
|
107
129
|
.on('dragstart', '.myplayer-progress', (e) => {
|
|
108
130
|
if (e.originalEvent) {
|
|
109
131
|
this.progressDragStart(e.originalEvent);
|
|
@@ -167,6 +189,7 @@ VideoPlayer.prototype.pause = function() {
|
|
|
167
189
|
}
|
|
168
190
|
|
|
169
191
|
VideoPlayer.prototype.stop = function() {
|
|
192
|
+
console.log('stop');
|
|
170
193
|
const video = this.$container.find('video')[0];
|
|
171
194
|
video.pause();
|
|
172
195
|
video.currentTime = 0;
|
|
@@ -226,7 +249,7 @@ VideoPlayer.prototype.hideControlsWithDelay = function() {
|
|
|
226
249
|
this.state.controlsDelayStart = Date.now();
|
|
227
250
|
setTimeout(() => {
|
|
228
251
|
const nowTime = Date.now();
|
|
229
|
-
console.debug("nowTime - this.state.controlsDelayStart", nowTime - this.state.controlsDelayStart);
|
|
252
|
+
// console.debug("nowTime - this.state.controlsDelayStart", nowTime - this.state.controlsDelayStart);
|
|
230
253
|
|
|
231
254
|
// 有时正常时间差也会小于设定的时间,所以判断时减去100ms
|
|
232
255
|
if (this.state.playing === true && nowTime - this.state.controlsDelayStart >= this.options.autoHideControlsDelayMs - 100) {
|
|
@@ -245,21 +268,38 @@ VideoPlayer.prototype.startUpdatingProgress = function() {
|
|
|
245
268
|
|
|
246
269
|
VideoPlayer.prototype.updateProgress = function() {
|
|
247
270
|
const video = this.$container.find('video')[0];
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
271
|
+
if (!video) return;
|
|
272
|
+
|
|
273
|
+
const currentTime = video.currentTime || 0;
|
|
274
|
+
const duration = video.duration || 0;
|
|
275
|
+
|
|
276
|
+
// 防止duration为NaN或0时计算出错
|
|
277
|
+
if (duration && !isNaN(duration) && duration > 0) {
|
|
278
|
+
const progress = currentTime / duration;
|
|
279
|
+
const parentWidth = this.$container.find('.myplayer-progress').width();
|
|
280
|
+
this.$container.find('.myplayer-subprogress').width(`${progress * parentWidth}px`);
|
|
281
|
+
//当progress为1时,将暂停按钮隐藏,播放按钮显示
|
|
282
|
+
if (progress >= 1) {
|
|
283
|
+
this.$container.find('.myplayer-btn-pause').hide();
|
|
284
|
+
this.$container.find('.myplayer-btn-play').show();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
254
287
|
|
|
255
|
-
|
|
288
|
+
// 格式化当前播放时间(currentTime单位为秒)
|
|
289
|
+
this.$container.find('.myplayer-playtime').html(formatTime(currentTime));
|
|
256
290
|
}
|
|
257
291
|
|
|
258
292
|
VideoPlayer.prototype.updateTotalTime = function() {
|
|
259
293
|
const video = this.$container.find('video')[0];
|
|
294
|
+
if (!video) return;
|
|
295
|
+
|
|
260
296
|
const duration = video.duration;
|
|
261
|
-
|
|
262
|
-
|
|
297
|
+
|
|
298
|
+
// 只有当duration有效时才更新显示
|
|
299
|
+
if (duration && !isNaN(duration) && isFinite(duration) && duration > 0) {
|
|
300
|
+
// duration单位为秒
|
|
301
|
+
this.$container.find('.myplayer-totaltime').html(formatTime(duration));
|
|
302
|
+
}
|
|
263
303
|
}
|
|
264
304
|
|
|
265
305
|
VideoPlayer.prototype.toggleFullScreen = function() {
|
|
@@ -270,16 +310,22 @@ VideoPlayer.prototype.toggleFullScreen = function() {
|
|
|
270
310
|
const innerContainer = $container.find('.myplayer-container');
|
|
271
311
|
|
|
272
312
|
if (innerContainer.hasClass('myplayer-full-screen')) {
|
|
313
|
+
// 退出全屏:将容器移回原位置
|
|
314
|
+
this._moveBackToOriginal();
|
|
273
315
|
innerContainer.removeClass('myplayer-full-screen');
|
|
274
316
|
bottom.removeClass('myplayer-full-screen');
|
|
275
317
|
fullScreenBtn.show();
|
|
276
318
|
exitFullScreenBtn.hide();
|
|
319
|
+
this.state.isFullScreen = false;
|
|
277
320
|
this.options.stateChanged.call(this, 'exitFullScreen');
|
|
278
321
|
} else {
|
|
322
|
+
// 进入全屏:将容器移动到body
|
|
323
|
+
this._moveToBody();
|
|
279
324
|
innerContainer.addClass('myplayer-full-screen');
|
|
280
325
|
bottom.addClass('myplayer-full-screen');
|
|
281
326
|
fullScreenBtn.hide();
|
|
282
327
|
exitFullScreenBtn.show();
|
|
328
|
+
this.state.isFullScreen = true;
|
|
283
329
|
this.options.stateChanged.call(this, 'enterFullScreen');
|
|
284
330
|
}
|
|
285
331
|
|
|
@@ -294,22 +340,83 @@ VideoPlayer.prototype.setFullScreen = function (target = true) {
|
|
|
294
340
|
const innerContainer = $container.find('.myplayer-container');
|
|
295
341
|
|
|
296
342
|
if (!target && innerContainer.hasClass('myplayer-full-screen')) {
|
|
343
|
+
// 退出全屏:将容器移回原位置
|
|
344
|
+
this._moveBackToOriginal();
|
|
297
345
|
innerContainer.removeClass('myplayer-full-screen');
|
|
298
346
|
bottom.removeClass('myplayer-full-screen');
|
|
299
347
|
fullScreenBtn.show();
|
|
300
348
|
exitFullScreenBtn.hide();
|
|
349
|
+
this.state.isFullScreen = false;
|
|
301
350
|
this.options.stateChanged.call(this, 'exitFullScreen');
|
|
302
351
|
} else if (target && !innerContainer.hasClass('myplayer-full-screen')) {
|
|
352
|
+
// 进入全屏:将容器移动到body
|
|
353
|
+
this._moveToBody();
|
|
303
354
|
innerContainer.addClass('myplayer-full-screen');
|
|
304
355
|
bottom.addClass('myplayer-full-screen');
|
|
305
356
|
fullScreenBtn.hide();
|
|
306
357
|
exitFullScreenBtn.show();
|
|
358
|
+
this.state.isFullScreen = true;
|
|
307
359
|
this.options.stateChanged.call(this, 'enterFullScreen');
|
|
308
360
|
}
|
|
309
361
|
|
|
310
362
|
this.hideControlsWithDelay();
|
|
311
363
|
}
|
|
312
364
|
|
|
365
|
+
/**
|
|
366
|
+
* 将容器移动到body(进入全屏时调用)
|
|
367
|
+
* @private
|
|
368
|
+
*/
|
|
369
|
+
VideoPlayer.prototype._moveToBody = function() {
|
|
370
|
+
const containerEl = this.$container[0];
|
|
371
|
+
|
|
372
|
+
// 保存原始位置信息(仅在第一次移动时保存)
|
|
373
|
+
if (!this.state.originalParent) {
|
|
374
|
+
this.state.originalParent = containerEl.parentNode;
|
|
375
|
+
this.state.originalNextSibling = containerEl.nextSibling;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// 从原容器解绑
|
|
379
|
+
this.$container.off();
|
|
380
|
+
// 从body解绑所有相关事件
|
|
381
|
+
$(document.body).off('click.myplayer');
|
|
382
|
+
$(document.body).off('canplay.myplayer');
|
|
383
|
+
$(document.body).off('dragstart.myplayer');
|
|
384
|
+
$(document.body).off('drag.myplayer');
|
|
385
|
+
$(document.body).off('dragend.myplayer');
|
|
386
|
+
|
|
387
|
+
// 移动到body
|
|
388
|
+
document.body.appendChild(containerEl);
|
|
389
|
+
|
|
390
|
+
// 重新绑定事件
|
|
391
|
+
this.bindEvent();
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 将容器移回原位置(退出全屏时调用)
|
|
396
|
+
* @private
|
|
397
|
+
*/
|
|
398
|
+
VideoPlayer.prototype._moveBackToOriginal = function() {
|
|
399
|
+
const containerEl = this.$container[0];
|
|
400
|
+
|
|
401
|
+
// 如果没有保存原始位置,说明还没移动过,直接返回
|
|
402
|
+
if (!this.state.originalParent) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// 解绑事件
|
|
407
|
+
this.$container.off();
|
|
408
|
+
|
|
409
|
+
// 移回原位置
|
|
410
|
+
if (this.state.originalNextSibling) {
|
|
411
|
+
this.state.originalParent.insertBefore(containerEl, this.state.originalNextSibling);
|
|
412
|
+
} else {
|
|
413
|
+
this.state.originalParent.appendChild(containerEl);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// 重新绑定事件
|
|
417
|
+
this.bindEvent();
|
|
418
|
+
}
|
|
419
|
+
|
|
313
420
|
/**
|
|
314
421
|
* 进度条拖动开始
|
|
315
422
|
* @param {MouseEvent} e
|
|
@@ -340,10 +447,14 @@ VideoPlayer.prototype.progressDrag = function(e) {
|
|
|
340
447
|
const video = $container.find('video')[0];
|
|
341
448
|
|
|
342
449
|
const parentWidth = progress.width();
|
|
343
|
-
|
|
450
|
+
// 使用getBoundingClientRect计算准确的点击位置
|
|
451
|
+
const rect = progress[0].getBoundingClientRect();
|
|
452
|
+
const clientX = e.clientX !== undefined ? e.clientX : (e.touches ? e.touches[0].clientX : 0);
|
|
453
|
+
const curOffset = Math.max(Math.min(clientX - rect.left, parentWidth), 0);
|
|
454
|
+
|
|
344
455
|
subprogress.width(`${curOffset}px`);
|
|
345
456
|
const adjustedPlayTime = curOffset / parentWidth * video.duration;
|
|
346
|
-
$container.find('.myplayer-playtime').html(formatTime(adjustedPlayTime
|
|
457
|
+
$container.find('.myplayer-playtime').html(formatTime(adjustedPlayTime));
|
|
347
458
|
}
|
|
348
459
|
|
|
349
460
|
/**
|
|
@@ -359,10 +470,19 @@ VideoPlayer.prototype.progressDragEnd = function(e) {
|
|
|
359
470
|
const video = $container.find('video')[0];
|
|
360
471
|
const progress = $container.find('.myplayer-progress');
|
|
361
472
|
const parentWidth = progress.width();
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
473
|
+
|
|
474
|
+
// 使用getBoundingClientRect计算准确的点击位置
|
|
475
|
+
const rect = progress[0].getBoundingClientRect();
|
|
476
|
+
const clientX = e.clientX !== undefined ? e.clientX : (e.touches ? e.touches[0].clientX : 0);
|
|
477
|
+
const curOffset = Math.max(Math.min(clientX - rect.left, parentWidth), 0);
|
|
478
|
+
|
|
479
|
+
// 计算目标播放时间(单位:秒)
|
|
480
|
+
const targetTime = (curOffset / parentWidth) * video.duration;
|
|
481
|
+
|
|
482
|
+
// 确保duration有效再设置currentTime
|
|
483
|
+
if (video.duration && !isNaN(video.duration) && video.duration > 0) {
|
|
484
|
+
video.currentTime = targetTime;
|
|
485
|
+
}
|
|
366
486
|
|
|
367
487
|
this.play();
|
|
368
488
|
|
|
@@ -12,11 +12,13 @@ const DEFAULTS = {
|
|
|
12
12
|
marginTop: 0, // 距离顶部距离
|
|
13
13
|
marginBottom: 12, // 最后一行距离底部距离
|
|
14
14
|
bufferHeight: '2rem', // 缓冲高度,进行可能的预先添加高度
|
|
15
|
+
startPoints: [], // 起始点坐标
|
|
15
16
|
data: [], // 数据源
|
|
16
17
|
container: '', // 容器元素
|
|
17
18
|
renderItem(data, index) { // 元素首次渲染时的回调函数, 如果把updateItem设置为空,那么更新时则会兜底触发renderItem
|
|
18
19
|
return '<div class="waterfall-item"></div>';
|
|
19
20
|
},
|
|
21
|
+
scrollDom: null, // 滚动元素,如果传入了滚动元素,那么用来计算的窗口高度就以滚动元素的高度为准
|
|
20
22
|
// 传入 $node, data, index
|
|
21
23
|
updateItem: null, // 元素更新时的回调函数
|
|
22
24
|
onscroll: null, // 滚动事件回调函数
|
|
@@ -86,6 +88,13 @@ export function Waterfall(optionsInput = {}) {
|
|
|
86
88
|
options.marginBottom = parseFloat(options.marginBottom);
|
|
87
89
|
}
|
|
88
90
|
}
|
|
91
|
+
options.startPoints.forEach((item, index) => {
|
|
92
|
+
if (item.constructor === String) {
|
|
93
|
+
options.startPoints[index] = remToPx(item);
|
|
94
|
+
} else {
|
|
95
|
+
item = parseFloat(item);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
89
98
|
|
|
90
99
|
const allWidth = $container.width();
|
|
91
100
|
this.allWidth = allWidth;
|
|
@@ -129,6 +138,8 @@ Waterfall.prototype.init = function () {
|
|
|
129
138
|
const $container = $(options.container);
|
|
130
139
|
const $scrollDom = options.scrollDom ? $(options.scrollDom) : $container;
|
|
131
140
|
|
|
141
|
+
this.$scrollDom = $scrollDom;
|
|
142
|
+
|
|
132
143
|
this.nodePool = []; // DOM 节点池
|
|
133
144
|
this.activeNodes = new Map(); // 当前活跃节点(索引 -> DOM)
|
|
134
145
|
this.allReadyNodes = new Map(); // 所有节点(索引 -> DOM)
|
|
@@ -177,11 +188,17 @@ Waterfall.prototype.init = function () {
|
|
|
177
188
|
Waterfall.prototype.updateVisibleItems = function (force = false) {
|
|
178
189
|
const self = this;
|
|
179
190
|
const options = this.options;
|
|
180
|
-
|
|
191
|
+
let h = 0;
|
|
192
|
+
if (options.scrollDom) {
|
|
193
|
+
h = $(options.scrollDom).height();
|
|
194
|
+
} else {
|
|
195
|
+
h = $(options.container).height();
|
|
196
|
+
}
|
|
181
197
|
|
|
182
198
|
const startTop = self.scrollTop; // 当前滚动位置
|
|
183
|
-
const endTop = startTop +
|
|
199
|
+
const endTop = startTop + h;
|
|
184
200
|
// console.log('startTop', startTop)
|
|
201
|
+
// console.log('endTop', endTop)
|
|
185
202
|
|
|
186
203
|
// 进行可见区域的渲染更新
|
|
187
204
|
this.updateCardsInView({
|
|
@@ -232,13 +249,13 @@ Waterfall.prototype.appendCard = function (data, dataId, { top, left }) {
|
|
|
232
249
|
}
|
|
233
250
|
|
|
234
251
|
// 获取指定高度下的卡片索引
|
|
235
|
-
Waterfall.prototype.updateCardsInView = function ({ start, end, force = false }) {
|
|
252
|
+
Waterfall.prototype.updateCardsInView = async function ({ start, end, force = false }) {
|
|
236
253
|
const options = this.options;
|
|
237
254
|
const minHeight = this.getMinHeight();
|
|
238
255
|
const endBuffer = end + options.bufferHeight;
|
|
239
256
|
if (minHeight < endBuffer) {
|
|
240
257
|
// 如果不够 进行补建
|
|
241
|
-
this.createCards({ end: endBuffer });
|
|
258
|
+
await this.createCards({ end: endBuffer });
|
|
242
259
|
}
|
|
243
260
|
|
|
244
261
|
const startNum = start - options.bufferHeight;
|
|
@@ -386,142 +403,154 @@ Waterfall.prototype.getMinHeight = function () {
|
|
|
386
403
|
Waterfall.prototype.getMinHeightColumn = function () {
|
|
387
404
|
let minHeight = -1;
|
|
388
405
|
let mimHeightColumn = null;
|
|
406
|
+
let index = -1;
|
|
407
|
+
const startPoints = this.options.startPoints || [];
|
|
389
408
|
for (let i = 0; i < this.columns; i++) {
|
|
390
409
|
const column = this.columnItems[i]
|
|
391
|
-
|
|
392
|
-
// 获取每组元素列表的最后一个bottom值
|
|
393
|
-
if (minHeight > column.bottom) {
|
|
410
|
+
if (minHeight === -1) {
|
|
394
411
|
minHeight = column.bottom;
|
|
395
412
|
mimHeightColumn = column;
|
|
396
|
-
|
|
413
|
+
index = i;
|
|
414
|
+
} else if (minHeight > column.bottom) {
|
|
415
|
+
// 获取每组元素列表的最后一个bottom值
|
|
397
416
|
minHeight = column.bottom;
|
|
398
417
|
mimHeightColumn = column;
|
|
418
|
+
index = i;
|
|
399
419
|
}
|
|
400
420
|
|
|
401
421
|
}
|
|
402
422
|
|
|
423
|
+
if (minHeight === 0 && index > -1) {
|
|
424
|
+
if (startPoints.length > index) {
|
|
425
|
+
// 设置一下起始点的初始化
|
|
426
|
+
mimHeightColumn.bottom = startPoints[index];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
403
430
|
return mimHeightColumn;
|
|
404
431
|
}
|
|
405
432
|
|
|
406
433
|
// 创建卡片
|
|
407
|
-
Waterfall.prototype.createCards = function ({ end, dataId = -1 }) {
|
|
434
|
+
Waterfall.prototype.createCards = function ({ end, dataId = -1 }, callback) {
|
|
408
435
|
const self = this;
|
|
409
436
|
const options = this.options;
|
|
410
|
-
const $container = $(options.container);
|
|
411
437
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
438
|
+
return new Promise((resolve) => {
|
|
439
|
+
// 新方案:获取下一个未渲染的数据ID
|
|
440
|
+
let nextDataId = null;
|
|
441
|
+
for (let [dataId, dataInfo] of this.dataIdMap) {
|
|
442
|
+
if (!this.renderedDataIds.has(dataId)) {
|
|
443
|
+
nextDataId = dataId;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
418
446
|
}
|
|
419
|
-
}
|
|
420
447
|
|
|
421
448
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
449
|
+
// 如果没有更多数据需要渲染
|
|
450
|
+
if (nextDataId === null) {
|
|
451
|
+
this.setScrollHeight();
|
|
452
|
+
return resolve();
|
|
453
|
+
}
|
|
429
454
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
455
|
+
const dataInfo = this.dataIdMap.get(nextDataId);
|
|
456
|
+
if (!dataInfo || !dataInfo.data) {
|
|
457
|
+
console.warn('Waterfall: Invalid data for dataId', nextDataId);
|
|
458
|
+
return resolve();
|
|
459
|
+
}
|
|
435
460
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
461
|
+
if (this.renderIndex >= options.data.length) {
|
|
462
|
+
this.setScrollHeight();
|
|
463
|
+
return resolve();
|
|
464
|
+
}
|
|
440
465
|
|
|
441
|
-
|
|
466
|
+
const data = options.data[nextDataId];
|
|
442
467
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
468
|
+
let column = this.getMinHeightColumn();
|
|
469
|
+
if (column === null) {
|
|
470
|
+
column = this.columnItems[0];
|
|
471
|
+
}
|
|
447
472
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
473
|
+
const top = column.bottom === 0 ? options.marginTop : (column.bottom + options.rowGap);
|
|
474
|
+
const position = { top, left: column.left };
|
|
475
|
+
const row = createDefaultRow(position);
|
|
451
476
|
|
|
452
|
-
|
|
477
|
+
this.renderIndex += 1;
|
|
453
478
|
|
|
454
|
-
|
|
479
|
+
let specialNode = false;
|
|
455
480
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
481
|
+
// 如果是特殊的卡片,需要指定节点不变更的数据,那么该数据的节点不能被其他数据使用
|
|
482
|
+
if (options.shouldOccupySpace) {
|
|
483
|
+
specialNode = options.shouldOccupySpace(data) || false;
|
|
484
|
+
}
|
|
460
485
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
$card = this.appendCard(data, nextDataId, position);
|
|
465
|
-
} else {
|
|
466
|
-
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
467
|
-
if ($tmp) {
|
|
468
|
-
$card = $tmp;
|
|
469
|
-
$card.css({
|
|
470
|
-
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
471
|
-
}).attr('data-index', nextDataId);
|
|
472
|
-
this.updateRenderUI($card, data, nextDataId);
|
|
473
|
-
} else {
|
|
486
|
+
// 添加卡片,使用dataId作为唯一标识
|
|
487
|
+
let $card = null;
|
|
488
|
+
if (this.nodePool.length === 0 || specialNode === true) {
|
|
474
489
|
$card = this.appendCard(data, nextDataId, position);
|
|
475
|
-
}
|
|
490
|
+
} else {
|
|
491
|
+
const $tmp = getNodePoolPop(this.nodePool, this.activeNodes);
|
|
492
|
+
if ($tmp) {
|
|
493
|
+
$card = $tmp;
|
|
494
|
+
$card.css({
|
|
495
|
+
'transform': `translate(${row.left}px,${row.top}px)`,
|
|
496
|
+
}).attr('data-index', nextDataId);
|
|
497
|
+
this.updateRenderUI($card, data, nextDataId);
|
|
476
498
|
|
|
477
|
-
|
|
499
|
+
} else {
|
|
500
|
+
$card = this.appendCard(data, nextDataId, position);
|
|
501
|
+
}
|
|
478
502
|
|
|
479
|
-
|
|
480
|
-
row.dataId = nextDataId; // 使用dataId替代renderIndex
|
|
481
|
-
if (dataId !== -1) {
|
|
482
|
-
row.dataId = dataId;
|
|
483
|
-
}
|
|
503
|
+
}
|
|
484
504
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
// };
|
|
505
|
+
row.$node = $card;
|
|
506
|
+
row.dataId = nextDataId; // 使用dataId替代renderIndex
|
|
507
|
+
if (dataId !== -1) {
|
|
508
|
+
row.dataId = dataId;
|
|
509
|
+
}
|
|
491
510
|
|
|
511
|
+
if (specialNode === false) {
|
|
512
|
+
// 把新增的卡片放进 activeNodes 当成活跃节点元素,那么是 可以动态使用的
|
|
513
|
+
this.activeNodes.set(nextDataId, $card);
|
|
492
514
|
|
|
515
|
+
this.allReadyNodes.set(nextDataId, $card);
|
|
516
|
+
} else {
|
|
517
|
+
// 如果是特殊的,这里不要记录了
|
|
518
|
+
this.allReadyNodes.set(nextDataId, null);
|
|
519
|
+
}
|
|
493
520
|
|
|
521
|
+
this.renderedDataIds.add(nextDataId);
|
|
494
522
|
|
|
495
|
-
|
|
496
|
-
//
|
|
497
|
-
this.activeNodes.set(nextDataId, $card);
|
|
523
|
+
// setTimeout(() => {
|
|
524
|
+
//window.requestAnimationFrame(() => {
|
|
498
525
|
|
|
499
|
-
|
|
500
|
-
} else {
|
|
501
|
-
// 如果是特殊的,这里不要记录了
|
|
502
|
-
this.allReadyNodes.set(nextDataId, null);
|
|
503
|
-
}
|
|
526
|
+
column.bottom = top + $card.height();
|
|
504
527
|
|
|
505
|
-
|
|
528
|
+
column.children.push(row);
|
|
529
|
+
row.bottom = column.bottom;
|
|
506
530
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
row.bottom = column.bottom;
|
|
531
|
+
// 检查是否需要继续创建卡片
|
|
532
|
+
const minHeight = this.getMinHeight();
|
|
533
|
+
const hasMoreData = this.renderedDataIds.size < this.dataIdMap.size;
|
|
511
534
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
535
|
+
if (hasMoreData && (minHeight < end)) {
|
|
536
|
+
|
|
537
|
+
this.createCards({ end }, () => {
|
|
538
|
+
resolve();
|
|
539
|
+
if (callback) {
|
|
540
|
+
callback();
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
} else {
|
|
544
|
+
this.setScrollHeight();
|
|
545
|
+
resolve();
|
|
546
|
+
if (callback) {
|
|
547
|
+
callback();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
//});
|
|
551
|
+
// }, 42);
|
|
552
|
+
});
|
|
515
553
|
|
|
516
|
-
if (hasMoreData && (minHeight < end)) {
|
|
517
|
-
window.requestAnimationFrame(() => {
|
|
518
|
-
this.createCards({ end });
|
|
519
|
-
});
|
|
520
|
-
} else {
|
|
521
|
-
// const maxHeight = this.getMaxHeight();
|
|
522
|
-
// $(options.container).find('.waterfall-list-scroll').css('height', maxHeight + options.marginBottom + 'px');
|
|
523
|
-
this.setScrollHeight();
|
|
524
|
-
}
|
|
525
554
|
}
|
|
526
555
|
|
|
527
556
|
|
|
@@ -564,7 +593,7 @@ Waterfall.prototype.updateRenderUI = function ($node, data, dataId) {
|
|
|
564
593
|
|
|
565
594
|
|
|
566
595
|
|
|
567
|
-
Waterfall.prototype.updateData = function (newData) {
|
|
596
|
+
Waterfall.prototype.updateData = async function (newData) {
|
|
568
597
|
const options = this.options;
|
|
569
598
|
options.data = newData;
|
|
570
599
|
|
|
@@ -574,23 +603,45 @@ Waterfall.prototype.updateData = function (newData) {
|
|
|
574
603
|
//this.nextDataId = 0;
|
|
575
604
|
|
|
576
605
|
// 为每个数据项分配唯一ID
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
this.createCards({ end: 0, dataId });
|
|
606
|
+
let bool = true
|
|
607
|
+
let count = options.data.length - 1;
|
|
608
|
+
let index = 0;
|
|
609
|
+
|
|
610
|
+
while (bool) {
|
|
611
|
+
if (index > count) {
|
|
612
|
+
bool = false
|
|
613
|
+
this.updateVisibleItems(true); // 强制更新渲染
|
|
614
|
+
break;
|
|
587
615
|
}
|
|
588
|
-
});
|
|
589
616
|
|
|
590
|
-
|
|
617
|
+
const dataId = index;
|
|
618
|
+
this.dataIdMap.set(dataId, {
|
|
619
|
+
data: true,
|
|
620
|
+
originalIndex: dataId,
|
|
621
|
+
layoutInfo: null
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
await this.createCards({ end: 0, dataId })
|
|
625
|
+
|
|
626
|
+
index += 1;
|
|
627
|
+
|
|
628
|
+
}
|
|
629
|
+
// options.data.forEach((item, index) => {
|
|
630
|
+
// const dataId = index; // this.nextDataId++;
|
|
631
|
+
// if (!this.allReadyNodes.has(dataId)) {
|
|
632
|
+
// this.dataIdMap.set(dataId, {
|
|
633
|
+
// data: true,// item,
|
|
634
|
+
// originalIndex: index,
|
|
635
|
+
// layoutInfo: null // 将在布局时填充
|
|
636
|
+
// });
|
|
637
|
+
// // 如果没有准备好这个数据,这里要创建一个占位节点
|
|
638
|
+
// this.createCards({ end: 0, dataId });
|
|
639
|
+
// }
|
|
640
|
+
// });
|
|
641
|
+
|
|
642
|
+
// this.updateVisibleItems(true); // 强制更新渲染
|
|
643
|
+
|
|
591
644
|
|
|
592
|
-
// 重新计算所有卡片位置并更新位置
|
|
593
|
-
// this.updatePointCards();
|
|
594
645
|
}
|
|
595
646
|
|
|
596
647
|
// 某个数据进行了UI变更,触发高度重新绘制
|
|
@@ -702,12 +753,16 @@ Waterfall.prototype.updatePointCards = function () {
|
|
|
702
753
|
Waterfall.prototype.showLoading = function (callback = null) {
|
|
703
754
|
this.isShowLoading = true;
|
|
704
755
|
const options = this.options;
|
|
705
|
-
const $container = $(options.container);
|
|
706
756
|
let $node = null
|
|
707
757
|
if (this.$loadingNode) {
|
|
708
758
|
let loadingTop = this.getMaxHeight() + options.rowGap
|
|
709
759
|
this.$loadingNode.css('transform', `translate(0px,${loadingTop}px)`);
|
|
710
|
-
$node = this.$loadingNode
|
|
760
|
+
$node = this.$loadingNode;
|
|
761
|
+
window.requestAnimationFrame(() => {
|
|
762
|
+
setTimeout(() => {
|
|
763
|
+
this.$scrollDom.scrollTop(loadingTop + this.$loadingNode.height());
|
|
764
|
+
});
|
|
765
|
+
});
|
|
711
766
|
}
|
|
712
767
|
|
|
713
768
|
if (callback) callback($node)
|
|
@@ -718,7 +773,6 @@ Waterfall.prototype.showLoading = function (callback = null) {
|
|
|
718
773
|
Waterfall.prototype.hideLoading = function (callback = null) {
|
|
719
774
|
this.isShowLoading = false;
|
|
720
775
|
const options = this.options;
|
|
721
|
-
const $container = $(options.container);
|
|
722
776
|
let $node = null
|
|
723
777
|
if (this.$loadingNode) {
|
|
724
778
|
let h1 = this.getMaxHeight() + options.marginBottom
|
|
@@ -726,14 +780,6 @@ Waterfall.prototype.hideLoading = function (callback = null) {
|
|
|
726
780
|
//如果要设置高度,那么这里判断一下当前是否正在做updata 一般这里被调用时,数据已经读到,在updata的同一时间调用了该函数
|
|
727
781
|
// 如果两个时刻高度是一致的 那么数据就是一致的 这里重新设置回来高度即可
|
|
728
782
|
window.requestAnimationFrame(() => {
|
|
729
|
-
// let h2 = this.getMaxHeight() + options.marginBottom
|
|
730
|
-
// if (h1 === h2) {
|
|
731
|
-
// const $scroll = $(options.container).find('.waterfall-list-scroll')
|
|
732
|
-
// const h = $scroll.height()
|
|
733
|
-
// if (h !== h1) {
|
|
734
|
-
// $scroll.css('height', h1 + 'px');
|
|
735
|
-
// }
|
|
736
|
-
// }
|
|
737
783
|
this.setScrollHeight();
|
|
738
784
|
})
|
|
739
785
|
$node = this.$loadingNode
|
|
@@ -796,4 +842,5 @@ function getNodePoolPop(nodePool, actives) {
|
|
|
796
842
|
}
|
|
797
843
|
}
|
|
798
844
|
return null;
|
|
799
|
-
}
|
|
845
|
+
}
|
|
846
|
+
|