@dolphinweex/weex-harmony 0.1.27 → 0.1.28

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.
@@ -4,106 +4,113 @@
4
4
  :class="{ editMode: data.isEditing }"
5
5
  :style="gridItemStyle"
6
6
  >
7
- <div class="grid-items-wrapper">
8
- <transition-group name="grid-fade" tag="div" class="grid-inner-wrapper">
9
- <div
10
- v-for="(item, index) in processedList"
11
- :key="item.itemView.id"
12
- class="grid-item"
13
- :class="{
14
- 'being-dragged': draggingIndex === index,
15
- hidden: isDragClone && draggingIndex === index,
16
- 'hover-target': hoverIndex === index && draggingIndex !== index,
17
- 'disabled-item': item.itemView.enable === false,
18
- }"
19
- :style="{
20
- overflow: data.isEditing ? 'visible' : 'hidden',
21
- }"
22
- @touchstart="(event) => startLongPress(event, index)"
23
- @touchmove="checkLongPressMove"
24
- @touchend="endTouch"
25
- @touchcancel="endTouch"
26
- :data-index="index"
27
- >
28
- <div
29
- v-if="item.bgAnimView && item.bgAnimView.animUrl && !data.isEditing"
30
- class="lottie-container bg-anim"
31
- :style="applyNormalAttribute(item.bgAnimView)"
32
- :ref="`bgAnim-${item.itemView.id}`"
33
- ></div>
34
- <div
35
- v-if="
36
- item.frontAnimView &&
37
- item.frontAnimView.animUrl &&
38
- !data.isEditing
39
- "
40
- class="lottie-container front-anim"
41
- :style="applyNormalAttribute(item.frontAnimView)"
42
- :ref="`frontAnim-${item.itemView.id}`"
43
- ></div>
7
+ <div class="items-container">
8
+ <div class="grid-items-wrapper">
9
+ <transition-group name="grid-fade" tag="div" class="grid-inner-wrapper">
44
10
  <div
45
- :style="applyNormalAttribute(item.itemView)"
46
- class="grid-box"
47
- :class="{ shaking: data.isEditing }"
48
- @click.stop="(e) => itemViewClick(e, item, index)"
49
-
11
+ v-for="(item, index) in processedList"
12
+ :key="item.itemView.id"
13
+ class="grid-item"
14
+ :class="{
15
+ 'being-dragged': draggingIndex === index,
16
+ hidden: isDragClone && draggingIndex === index,
17
+ 'hover-target': hoverIndex === index && draggingIndex !== index,
18
+ 'disabled-item': item.itemView.enable === false,
19
+ }"
20
+ :style="{
21
+ overflow: data.isEditing ? 'visible' : 'hidden',
22
+ }"
23
+ :data-index="index"
24
+ @touchstart="(event) => startLongPress(event, index)"
25
+ @touchmove="checkLongPressMove"
26
+ @touchend="endTouch"
27
+ @touchcancel="endTouch"
50
28
  >
51
- <div class="flexBox">
52
- <img
53
- :src="item.iconImage.url"
54
- :style="applyNormalAttribute(item.iconImage)"
55
- />
56
- <div>
57
- <div @click.stop.prevent v-if="!data.isEditing">
58
- <button
59
- class="actionButton"
60
- @click.stop.prevent="(e) => actionClick(e, item, index)"
61
- :style="applyNormalAttribute(item.actionButton)"
62
- >
63
- {{ item.actionButton.text }}
64
- </button>
65
- <div
66
- v-if="item.loadingAnimView && item.loadingAnimView.animUrl"
67
- class="loading-anim"
68
- :style="applyNormalAttribute(item.loadingAnimView)"
69
- :ref="`loadingAnim-${item.itemView.id}`"
70
- ></div>
71
- </div>
72
- <div @click.stop.prevent v-if="!data.isEditing">
73
- <img
74
- :src="item.rightIcon.url"
75
- :style="applyNormalAttribute(item.rightIcon)"
76
- @click.stop.prevent="(e) => rightIconClick(e)"
77
- />
78
- </div>
79
- <div @click.stop.prevent v-if="!data.isEditing">
80
- <img
81
- class="leftTopIcon"
82
- :src="item.leftTopIcon.url"
83
- :style="applyNormalAttribute(item.leftTopIcon)"
84
- @click.stop.prevent
85
- />
86
- </div>
87
- <div @click.stop.prevent v-if="data.isEditing">
88
- <img
89
- class="isSelected"
90
- @click.stop.prevent="(e) => selectIconClick(e, item, index)"
91
- :src="
92
- item.itemView.isSelected
93
- ? item.selectIcon.selectedUrl
94
- : item.selectIcon.url
95
- "
96
- :style="applyNormalAttribute(item.selectIcon)"
97
- />
29
+ <div
30
+ v-if="
31
+ item.bgAnimView && item.bgAnimView.animUrl && !data.isEditing
32
+ "
33
+ class="lottie-container bg-anim"
34
+ :style="applyNormalAttribute(item.bgAnimView)"
35
+ :ref="`bgAnim-${item.itemView.id}`"
36
+ ></div>
37
+ <div
38
+ v-if="
39
+ item.frontAnimView &&
40
+ item.frontAnimView.animUrl &&
41
+ !data.isEditing
42
+ "
43
+ class="lottie-container front-anim"
44
+ :style="applyNormalAttribute(item.frontAnimView)"
45
+ :ref="`frontAnim-${item.itemView.id}`"
46
+ ></div>
47
+ <div
48
+ :style="applyNormalAttribute(item.itemView)"
49
+ class="grid-box"
50
+ :class="{ shaking: data.isEditing }"
51
+ @click.stop="(e) => itemViewClick(e, item, index)"
52
+ >
53
+ <div class="flexBox">
54
+ <img
55
+ :src="item.iconImage.url"
56
+ :style="applyNormalAttribute(item.iconImage)"
57
+ />
58
+ <div>
59
+ <div @click.stop.prevent v-if="!data.isEditing">
60
+ <button
61
+ class="actionButton"
62
+ @click.stop.prevent="(e) => actionClick(e, item, index)"
63
+ :style="applyNormalAttribute(item.actionButton)"
64
+ >
65
+ {{ item.actionButton.text }}
66
+ </button>
67
+ <div
68
+ v-if="
69
+ item.loadingAnimView && item.loadingAnimView.animUrl
70
+ "
71
+ class="loading-anim"
72
+ :style="applyNormalAttribute(item.loadingAnimView)"
73
+ :ref="`loadingAnim-${item.itemView.id}`"
74
+ ></div>
75
+ </div>
76
+ <div @click.stop.prevent v-if="!data.isEditing">
77
+ <img
78
+ :src="item.rightIcon.url"
79
+ :style="applyNormalAttribute(item.rightIcon)"
80
+ @click.stop.prevent="(e) => rightIconClick(e)"
81
+ />
82
+ </div>
83
+ <div @click.stop.prevent v-if="!data.isEditing">
84
+ <img
85
+ class="leftTopIcon"
86
+ :src="item.leftTopIcon.url"
87
+ :style="applyNormalAttribute(item.leftTopIcon)"
88
+ @click.stop.prevent
89
+ />
90
+ </div>
91
+ <div @click.stop.prevent v-if="data.isEditing">
92
+ <img
93
+ class="isSelected"
94
+ @click.stop.prevent="
95
+ (e) => selectIconClick(e, item, index)
96
+ "
97
+ :src="
98
+ item.itemView.isSelected
99
+ ? item.selectIcon.selectedUrl
100
+ : item.selectIcon.url
101
+ "
102
+ :style="applyNormalAttribute(item.selectIcon)"
103
+ />
104
+ </div>
98
105
  </div>
99
106
  </div>
100
- </div>
101
- <div class="itemText" :style="[applyNormalAttribute(item.text)]">
102
- {{ item.text.text }}
107
+ <div class="itemText" :style="[applyNormalAttribute(item.text)]">
108
+ {{ item.text.text }}
109
+ </div>
103
110
  </div>
104
111
  </div>
105
- </div>
106
- </transition-group>
112
+ </transition-group>
113
+ </div>
107
114
  </div>
108
115
 
109
116
  <!-- 拖拽克隆元素 -->
@@ -169,7 +176,7 @@ export default {
169
176
  processedList: [],
170
177
  selected: null,
171
178
  longPressTimer: null,
172
- longPressDuration: 400, // 略微延长长按时间,减少误触发
179
+ longPressDuration: 350,
173
180
  longPressStartIndex: null,
174
181
  draggingIndex: null,
175
182
  hoverIndex: null,
@@ -178,7 +185,6 @@ export default {
178
185
  isAnimating: false,
179
186
  touchStartX: 0,
180
187
  touchStartY: 0,
181
- touchStartTime: 0, // 记录触摸开始时间,用于计算滑动速度
182
188
  draggedItemRect: null,
183
189
  isDragClone: false,
184
190
  dragCloneX: 0,
@@ -188,17 +194,13 @@ export default {
188
194
  gridBoxWidth: 0,
189
195
  lottieAnimations: {},
190
196
  isScrolling: false,
191
- scrollThreshold: 8, // 增大滚动检测阈值
197
+ scrollThreshold: 5,
192
198
  fixedItemWidth: 0,
193
199
  fixedItemHeight: 0,
194
200
  animationFrameId: null,
195
201
  lastBestTarget: null,
196
202
  targetChangeTime: null,
197
203
  pendingTarget: null,
198
- weexListInnerEl: null,
199
- weexRefreshEl: null,
200
- originListInnerStyle: null,
201
- originRefreshStyle: null,
202
204
  };
203
205
  },
204
206
  computed: {
@@ -206,9 +208,6 @@ export default {
206
208
  return {
207
209
  '--grid-cols': this.data.spanCount || this.cols,
208
210
  '--grid-gap': `${this.data.spaceSize || 8}px`,
209
- '--grid-margin': `${
210
- this.data.layoutConfig.marginStart + this.data.layoutConfig.marginEnd
211
- }px`,
212
211
  marginTop: this.data.layoutConfig.marginTop * scla,
213
212
  marginBottom: this.data.layoutConfig.marginBottom * scla,
214
213
  marginLeft: this.data.layoutConfig.marginStart * scla,
@@ -252,14 +251,18 @@ export default {
252
251
  const dataIndex = this.data.list.findIndex(
253
252
  (item) => item.itemView.id == id
254
253
  );
255
- // 更新原始数据以确保watch能触发
256
- if(dataIndex !== -1) {
257
- // 使用Vue的$set确保响应式更新
258
- this.$set(this.data.list, dataIndex, JSON.parse(JSON.stringify(data)));
259
- }
254
+
260
255
  if (index === -1) {
261
256
  return;
262
257
  }
258
+
259
+ // 检查是否有动画URL的变化
260
+ const oldBgAnimUrl = this.processedList[index].bgAnimView.animUrl || '';
261
+ const oldLoadingAnimUrl =
262
+ this.processedList[index].loadingAnimView.animUrl || '';
263
+ const oldFrontAnimUrl =
264
+ this.processedList[index].frontAnimView.animUrl || '';
265
+
263
266
  const newBgAnimUrl = data.bgAnimView.animUrl || '';
264
267
  const newLoadingAnimUrl = data.loadingAnimView.animUrl || '';
265
268
  const newFrontAnimUrl = data.frontAnimView.animUrl || '';
@@ -267,40 +270,72 @@ export default {
267
270
  this.processedList[index] = data;
268
271
  this.processedList = [...this.processedList];
269
272
 
273
+ // 更新原始数据以确保watch能触发
274
+ if (dataIndex !== -1) {
275
+ // 使用Vue的$set确保响应式更新
276
+ this.$set(this.data.list, dataIndex, JSON.parse(JSON.stringify(data)));
277
+ }
270
278
 
271
- // 无论是否有URL变化,都处理动画更新
272
- // 这样确保任何visibility或其他属性变化也能被处理
279
+ // 如果动画URL有变化,重新初始化相关的Lottie动画
280
+ console.log('检测到动画URL变化,重新初始化动画');
281
+
282
+ // 等待下一帧DOM更新完成后再操作
273
283
  this.$nextTick(() => {
274
284
  // 清理旧的动画实例
275
285
  const itemId = String(data.itemView.id);
276
- // 加载背景动画
277
- if (newBgAnimUrl) {
278
- this.loadLottieAnimation(
279
- data.bgAnimView,
280
- `bgAnim-${itemId}`,
281
- `bg-${itemId}`,
282
- data,
283
- dataIndex
284
- );
285
- }
286
- if (newLoadingAnimUrl) {
287
- this.loadLottieAnimation(
288
- data.loadingAnimView,
289
- `loadingAnim-${itemId}`,
290
- `loading-${itemId}`,
291
- data,
292
- dataIndex
293
- );
294
- }
295
- if (newFrontAnimUrl) {
296
- this.loadLottieAnimation(
297
- data.frontAnimView,
298
- `frontAnim-${itemId}`,
299
- `front-${itemId}`,
300
- data,
301
- dataIndex
302
- );
303
- }
286
+
287
+ // 清除所有相关的动画实例
288
+ const animKeys = [
289
+ `bg-${itemId}`,
290
+ `loading-${itemId}`,
291
+ `front-${itemId}`,
292
+ ];
293
+ animKeys.forEach((key) => {
294
+ if (this.lottieAnimations[key]) {
295
+ console.log(`销毁动画实例: ${key}`);
296
+ const anim = this.lottieAnimations[key];
297
+ try {
298
+ anim.removeEventListener('complete');
299
+ } catch (e) {
300
+ console.warn(`移除事件监听器失败: ${e.message}`);
301
+ }
302
+ anim.destroy();
303
+ delete this.lottieAnimations[key];
304
+ }
305
+ });
306
+
307
+ console.log('清理完成,开始重新初始化动画');
308
+
309
+ // 延迟一点时间确保DOM完全更新
310
+ setTimeout(() => {
311
+ // 重新初始化背景动画
312
+ if (oldBgAnimUrl !== newBgAnimUrl) {
313
+ this.loadLottieAnimation(
314
+ data.bgAnimView,
315
+ `bgAnim-${itemId}`,
316
+ `bg-${itemId}`,
317
+ data
318
+ );
319
+ }
320
+
321
+ if (oldLoadingAnimUrl !== newLoadingAnimUrl) {
322
+ this.loadLottieAnimation(
323
+ data.loadingAnimView,
324
+ `loadingAnim-${itemId}`,
325
+ `loading-${itemId}`,
326
+ data
327
+ );
328
+ }
329
+
330
+ if (oldFrontAnimUrl !== newFrontAnimUrl) {
331
+ this.loadLottieAnimation(
332
+ data.frontAnimView,
333
+ `frontAnim-${itemId}`,
334
+ `front-${itemId}`,
335
+ data
336
+ );
337
+ }
338
+ }, 100); // 增加延迟确保DOM已更新和旧动画已完全销毁
304
339
  });
305
340
  },
306
341
  getListData(callback) {
@@ -315,6 +350,7 @@ export default {
315
350
  callback({ listData: data });
316
351
  },
317
352
  rightIconClick(e) {
353
+ console.log('rightIconClick执行,阻止事件冒泡');
318
354
  e.preventDefault();
319
355
  e.stopPropagation();
320
356
  this.$emit('onClickRightIcon', e);
@@ -329,7 +365,9 @@ export default {
329
365
  selectIconClick(e, item, index) {
330
366
  e.preventDefault();
331
367
  e.stopPropagation(); // 阻止事件冒泡到itemViewClick
332
- item.itemView.isSelected = !item.itemView.isSelected;
368
+ if (item.selectIcon.visibility) {
369
+ item.itemView.isSelected = !item.itemView.isSelected;
370
+ }
333
371
  const target = {
334
372
  ...item.itemView,
335
373
  id: String(item.itemView.id),
@@ -346,27 +384,37 @@ export default {
346
384
  if (e.defaultPrevented) {
347
385
  return;
348
386
  }
349
- e.preventDefault();
350
- e.stopPropagation();
351
- // 确保取消任何长按计时器
352
- this.cancelLongPress();
353
- if (this.data.isEditing) {
354
- item.itemView.isSelected = !item.itemView.isSelected;
355
- this.$emit('onSelectItems', target);
356
- return;
357
- }
358
387
  const target = {
359
388
  ...item.itemView,
360
389
  id: String(item.itemView.id),
361
390
  index,
362
391
  ...e,
363
392
  };
393
+ console.log('itemViewClick');
394
+ // 确保取消任何长按计时器
395
+ this.cancelLongPress();
396
+ if (this.data.isEditing) {
397
+ if (item.selectIcon.visibility) {
398
+ item.itemView.isSelected = !item.itemView.isSelected;
399
+ }
400
+ return;
401
+ }
402
+ e.preventDefault();
403
+ e.stopPropagation();
404
+
364
405
  this.$emit('onClickItem', target);
406
+ this.data.isEditing&&item.selectIcon.visibility&&this.$emit('onSelectItems', target);
407
+
365
408
  },
366
409
 
367
410
  actionClick(e, item, index) {
411
+ console.log('actionClick执行,阻止事件冒泡');
368
412
  e.preventDefault();
369
413
  e.stopPropagation(); // 阻止事件冒泡到itemViewClick
414
+
415
+ // 在触发事件前,先清理所有其他项目的动画实例
416
+ this.cleanupOtherAnimations(item.itemView.id);
417
+
370
418
  const target = {
371
419
  ...item.itemView,
372
420
  id: String(item.itemView.id),
@@ -377,6 +425,58 @@ export default {
377
425
  return false;
378
426
  },
379
427
 
428
+ // 新增方法:清理除指定项目外的所有动画实例
429
+ cleanupOtherAnimations(currentItemId) {
430
+ console.log('清理其他项目的动画实例,当前项目ID:', currentItemId);
431
+
432
+ Object.keys(this.lottieAnimations).forEach((key) => {
433
+ if (!key.includes(`-${currentItemId}`)) {
434
+ if (this.lottieAnimations[key]) {
435
+ console.log(`销毁其他项目的动画实例: ${key}`);
436
+ const anim = this.lottieAnimations[key];
437
+
438
+ // 不要立即销毁,而是先停止动画
439
+ anim.pause();
440
+
441
+ // 使用 setTimeout 延迟销毁,给新动画一个启动的时间
442
+ setTimeout(() => {
443
+ try {
444
+ if (this.lottieAnimations[key] === anim) {
445
+ anim.removeEventListener('complete');
446
+ anim.destroy();
447
+ delete this.lottieAnimations[key];
448
+
449
+ // 提取项目ID和动画类型
450
+ const parts = key.split('-');
451
+ if (parts.length === 2) {
452
+ const animType = parts[0];
453
+ const itemId = parts[1];
454
+
455
+ // 延迟隐藏对应的动画容器
456
+ this.$nextTick(() => {
457
+ const refName = `${animType}Anim-${itemId}`;
458
+ const animContainer =
459
+ this.$refs[refName] && this.$refs[refName][0];
460
+ if (animContainer) {
461
+ // 使用 opacity 过渡而不是直接设置 display: none
462
+ animContainer.style.opacity = '0';
463
+ animContainer.style.transition = 'opacity 0.2s';
464
+ setTimeout(() => {
465
+ animContainer.style.display = 'none';
466
+ }, 200);
467
+ }
468
+ });
469
+ }
470
+ }
471
+ } catch (e) {
472
+ console.warn(`清理动画失败: ${e.message}`);
473
+ }
474
+ }, 50);
475
+ }
476
+ }
477
+ });
478
+ },
479
+
380
480
  // 生成处理后的数据列表
381
481
  generateDataList() {
382
482
  if (!this.data || !this.data.list || !this.data.globalData) {
@@ -405,12 +505,12 @@ export default {
405
505
  // 使用mergeDate合并全局数据和项目数据
406
506
  processedItem[type] = this.mergeDate(item[type] || {}, type);
407
507
  });
408
-
409
508
  return processedItem;
410
509
  });
411
510
  },
412
511
  getItemStyle(item, type) {
413
512
  const result = this.mergeDate(item[type] || {}, type);
513
+ console.log(type, this.applyNormalAttribute(result), 'ggg');
414
514
  return this.applyNormalAttribute(result);
415
515
  },
416
516
  mergeDate(target, type) {
@@ -476,44 +576,43 @@ export default {
476
576
  },
477
577
  // 开始长按
478
578
  startLongPress(e, index) {
479
- console.log(e, 'cdj-------startLongPress');
480
579
  if (!this.data.isEditable) {
481
580
  return;
482
581
  }
483
-
484
- // 确保事件不被其他处理器抢先处理
485
- // e.oriEvent.stopPropagation();
486
-
582
+ this.$emit('onDragEventStart', e);
583
+
584
+ // 只在编辑模式下阻止事件冒泡和默认行为
585
+ if (this.data.isEditing) {
586
+ if (e.oriEvent) {
587
+ // e.oriEvent.preventDefault();
588
+ // e.oriEvent.stopPropagation();
589
+ // e.oriEvent.stopImmediatePropagation();
590
+ }
591
+ // e.preventDefault && e.preventDefault();
592
+ // e.stopPropagation && e.stopPropagation();
593
+ // e.stopImmediatePropagation && e.stopImmediatePropagation();
594
+ }
595
+
487
596
  // 清除任何现有计时器
488
597
  this.cancelLongPress();
489
-
490
598
  // 记录起始触摸位置和索引
491
599
  const touch = e.changedTouches[0];
492
600
  this.touchStartX = touch.pageX;
493
601
  this.touchStartY = touch.pageY;
602
+ console.log('开始长按ddddddddd', touch, touch.pageY, touch.pageX);
494
603
  this.longPressStartIndex = index;
495
604
  this.isScrolling = false; // 重置滚动状态
496
605
 
497
- // 记录触摸开始时间,用于判断是否为快速滑动
498
- this.touchStartTime = Date.now();
499
-
500
- if (this.isTouchDragging) {
501
- this.$emit('drag-end', {
502
- items: [...this.itemsList],
503
- });
504
- }
505
-
506
- // 通知外部触摸开始事件
507
- this.$emit('onDragEventStart', e);
606
+ // 添加临时事件监听器,在长按期间阻止滚动
607
+ document.addEventListener('touchmove', this.onTouchMove, {
608
+ passive: false // 设置为false以允许阻止默认行为
609
+ });
508
610
 
509
- // 设置新的长按计时器 - 延长一点时间避免误触发
611
+ // 设置新的长按计时器
510
612
  this.longPressTimer = setTimeout(() => {
511
613
  // 只有在没有滚动的情况下才激活拖拽模式
512
614
  if (!this.isScrolling) {
513
- console.log('长按时间到,激活拖拽模式');
514
615
  this.activateDragMode(index);
515
- } else {
516
- console.log('检测到滚动,取消拖拽激活');
517
616
  }
518
617
  }, this.longPressDuration);
519
618
  },
@@ -525,109 +624,93 @@ export default {
525
624
  }
526
625
 
527
626
  const touch = e.changedTouches[0];
627
+ const moveX = Math.abs(touch.pageX - this.touchStartX);
628
+ const moveY = Math.abs(touch.pageY - this.touchStartY);
629
+
630
+ // 如果水平移动大于垂直移动,则阻止事件传播
631
+ if (moveX > moveY &&!this.isTouchDragging && this.data.isEditing) {
632
+ if (e.oriEvent) {
633
+ e.oriEvent.preventDefault();
634
+ e.oriEvent.stopPropagation();
635
+ e.oriEvent.stopImmediatePropagation();
636
+ e.preventDefault && e.preventDefault();
637
+ e.stopPropagation && e.stopPropagation();
638
+ e.stopImmediatePropagation && e.stopImmediatePropagation();
639
+ }
640
+ }
641
+
528
642
  // 如果已经在拖拽模式,交给onTouchMove处理
529
643
  if (this.isTouchDragging) {
530
644
  this.onTouchMove(e);
531
645
  return;
532
646
  }
533
647
 
534
- const moveX = Math.abs(touch.pageX - this.touchStartX);
535
- const moveY = Math.abs(touch.pageY - this.touchStartY);
536
-
537
- // 计算触摸移动速度 (像素/毫秒)
538
- const currentTime = Date.now();
539
- const timeDiff = currentTime - this.touchStartTime;
540
- const speedY = moveY / Math.max(1, timeDiff); // 垂直滑动速度
541
-
542
- // 速度检测:快速滑动可能表示滚动意图
543
- const isQuickSwipe = speedY > 0.5; // 如果垂直滑动速度大于0.5px/ms,判定为快速滑动
544
-
545
- // 更敏感地检测滚动意图
546
- // 1. 垂直移动显著大于水平移动
547
- // 2. 垂直移动超过阈值的两倍
548
- // 3. 快速垂直滑动
549
- if (
550
- (moveY > moveX * 1.2 && moveY > this.scrollThreshold) ||
551
- moveY > this.scrollThreshold * 2 ||
552
- (isQuickSwipe && moveY > this.scrollThreshold)
553
- ) {
554
- console.log('检测到滚动意图,取消长按', { moveY, moveX, speedY });
648
+ // 检测是否在滚动
649
+ if (moveY > this.scrollThreshold * 3) {
650
+ // 增加滚动阈值以更容易识别滚动意图
555
651
  this.isScrolling = true;
556
652
  this.cancelLongPress();
557
653
  return;
558
654
  }
559
655
 
560
- // 如果移动超过阈值,取消长按 - 但不阻止默认行为
656
+ // 如果移动超过阈值,取消长按
561
657
  if (moveX > this.scrollThreshold || moveY > this.scrollThreshold) {
562
658
  this.cancelLongPress();
563
- return;
564
659
  }
565
660
 
566
- // 只有确认不是滚动意图,且在长按倒计时中,才阻止默认行为
567
- if (this.longPressTimer && !this.isScrolling) {
568
- e.oriEvent.preventDefault();
569
- }
661
+ return false;
570
662
  },
571
663
 
572
664
  // 激活拖拽模式
573
665
  activateDragMode(index) {
574
666
  console.log('长按触发,进入编辑模式');
667
+ // 进入编辑模式
575
668
 
576
- // 先确保编辑模式已开启
577
- if (!this.data.isEditing) {
578
- // 设置编辑状态并隐藏weex-refresh
579
- this.data.isEditing = true;
580
- this.$emit('onEditStateChanged', true);
581
- } else {
582
- // 无论之前是否处于编辑模式,都设置拖拽状态
583
- // 设置当前拖拽索引
584
- this.draggingIndex = index;
585
- this.isTouchDragging = true;
586
- // 使用存储的固定宽高
587
- this.draggedItemRect = {
588
- width: this.fixedItemWidth,
589
- height: this.fixedItemHeight,
590
- };
591
-
592
- // 获取当前元素位置用于计算偏移
593
- const element = document.querySelectorAll('.grid-item')[index];
594
- if (element) {
595
- const rect = element.getBoundingClientRect();
596
- // 计算触摸点相对于元素左上角的偏移
597
- this.touchOffsetX = this.touchStartX - rect.left;
598
- this.touchOffsetY = this.touchStartY - rect.top;
599
-
600
- // 设置克隆元素的初始位置
601
- this.dragCloneX = rect.left;
602
- this.dragCloneY = rect.top;
603
-
604
- // 显示拖拽克隆
605
- this.isDragClone = true;
606
-
607
- // 禁止页面滚动
608
- document.body.style.overflow = 'hidden';
609
- document.body.style.touchAction = 'none';
610
-
611
- // 添加全局触摸事件处理,确保捕获所有触摸事件
612
- document.addEventListener('touchmove', this.onGlobalTouchMove, {
613
- passive: false,
614
- capture: true,
615
- });
616
- document.addEventListener('touchend', this.onTouchEnd, {
617
- passive: false,
618
- capture: true,
619
- });
669
+ if(this.data.isEditing){
670
+ // 设置当前拖拽索引
671
+ this.draggingIndex = index;
672
+ this.isTouchDragging = true;
620
673
 
621
- // 立即执行一次定位以确保初始位置准确
622
- requestAnimationFrame(() => {
623
- this.dragCloneX = this.touchStartX - this.touchOffsetX;
624
- this.dragCloneY = this.touchStartY - this.touchOffsetY;
625
- });
674
+ // 此时添加阻止默认行为的事件监听,但只影响拖拽状态下的行为
675
+ document.addEventListener('touchmove', this.onTouchMove, {
676
+ passive: false, // 只有在拖拽模式下才阻止默认行为
677
+ });
678
+ document.addEventListener('touchend', this.onTouchEnd, {
679
+ passive: true,
680
+ });
626
681
 
627
- console.log('拖拽克隆已创建');
628
- }
629
- }
682
+ // 使用存储的固定宽高
683
+ this.draggedItemRect = {
684
+ width: this.fixedItemWidth,
685
+ height: this.fixedItemHeight,
686
+ };
687
+
688
+ // 获取当前元素位置用于计算偏移
689
+ const element = document.querySelectorAll('.grid-item')[index];
690
+ if (element) {
691
+ const rect = element.getBoundingClientRect();
692
+ // 计算触摸点相对于元素左上角的偏移
693
+ this.touchOffsetX = this.touchStartX - rect.left;
694
+ this.touchOffsetY = this.touchStartY - rect.top;
695
+
696
+ // 设置克隆元素的初始位置
697
+ this.dragCloneX = rect.left;
698
+ this.dragCloneY = rect.top;
699
+
700
+ // 显示拖拽克隆
701
+ this.isDragClone = true;
702
+
703
+ // 立即执行一次定位以确保初始位置准确
704
+ requestAnimationFrame(() => {
705
+ this.dragCloneX = this.touchStartX - this.touchOffsetX;
706
+ this.dragCloneY = this.touchStartY - this.touchOffsetY;
707
+ });
630
708
 
709
+ console.log('拖拽克隆已创建');
710
+ }
711
+ }
712
+ this.data.isEditing = true;
713
+ this.$emit('onEditStateChanged', true);
631
714
  this.longPressTimer = null;
632
715
  },
633
716
 
@@ -638,45 +721,24 @@ export default {
638
721
  this.longPressTimer = null;
639
722
  }
640
723
  this.longPressStartIndex = null;
641
-
642
- // 确保不再阻止滚动
643
- if (this.isScrolling) {
644
- // 如果已经确定为滚动意图,应该立即恢复系统默认滚动行为
645
- document.body.style.overflow = '';
646
- document.body.style.touchAction = '';
647
- }
648
- },
649
-
650
- // 全局触摸移动处理 - 捕获阶段拦截所有触摸移动
651
- onGlobalTouchMove(e) {
652
- if (this.isTouchDragging) {
653
- // 在捕获阶段强制阻止默认行为,防止页面滚动
654
- e.preventDefault();
655
- e.stopPropagation();
656
-
657
- // 继续处理拖拽逻辑
658
- this.handleTouchMove(e);
659
- }
660
724
  },
661
725
 
662
726
  // 触摸移动处理
663
727
  onTouchMove(e) {
664
728
  if (!this.isTouchDragging) return;
665
729
 
666
- // 当处于拖拽状态时,阻止默认行为
667
- if (this.isTouchDragging) {
668
- e.oriEvent.preventDefault();
669
- e.oriEvent.stopPropagation();
730
+ // 确保在拖拽模式下阻止所有事件传播
731
+ if (this.isTouchDragging && this.data.isEditing) {
732
+ if (e.oriEvent) {
733
+ e.oriEvent.preventDefault();
734
+ e.oriEvent.stopPropagation();
735
+ e.oriEvent.stopImmediatePropagation(); // 添加这行以确保事件不会继续传播
736
+ }
737
+ e.preventDefault && e.preventDefault();
738
+ e.stopPropagation && e.stopPropagation();
739
+ e.stopImmediatePropagation && e.stopImmediatePropagation();
670
740
  }
671
741
 
672
- this.handleTouchMove(e);
673
- },
674
-
675
- // 抽取通用的触摸移动处理逻辑
676
- handleTouchMove(e) {
677
- console.log(this.isTouchDragging, 'this.isTouchDragging111111');
678
- if (!this.isTouchDragging) return;
679
-
680
742
  const touch = e.changedTouches[0];
681
743
 
682
744
  // 更新目标位置而非直接设置
@@ -731,9 +793,9 @@ export default {
731
793
  );
732
794
  const centerScore = 1 - distanceFromCenter;
733
795
 
734
- // 放宽元素中心区域的判定,让交换更容易触发
735
- // 降低阈值,让交换更敏感
736
- if (centerScore > maxCenterScore && centerScore > 0.2) {
796
+ // 只有当分数更高且高于阈值时才更新bestTarget
797
+ // 提高阈值到0.35,确保更稳定的交换判断
798
+ if (centerScore > maxCenterScore && centerScore > 0.35) {
737
799
  maxCenterScore = centerScore;
738
800
  bestTarget = itemIndex;
739
801
  }
@@ -743,24 +805,36 @@ export default {
743
805
  // 设置悬停高亮,仅当有合格的目标时才高亮
744
806
  this.hoverIndex = bestTarget;
745
807
 
746
- // 简化交换防抖动处理,让交换更直接响应
747
- if (bestTarget !== null) {
748
- // 直接使用当前的最佳目标
749
- this.lastBestTarget = bestTarget;
750
- } else {
751
- // 如果没有目标,清除lastBestTarget
752
- this.lastBestTarget = null;
808
+ // 增加交换防抖动处理
809
+ // 如果bestTarget变化但不等于上次的目标,先记录一下
810
+ if (this.lastBestTarget !== bestTarget && bestTarget !== null) {
811
+ if (!this.targetChangeTime) {
812
+ this.targetChangeTime = Date.now();
813
+ this.pendingTarget = bestTarget;
814
+ } else if (Date.now() - this.targetChangeTime > 100) {
815
+ // 只有当目标持续100ms稳定不变时,才认为是有效目标
816
+ this.lastBestTarget = this.pendingTarget;
817
+ this.targetChangeTime = null;
818
+ this.pendingTarget = null;
819
+ }
820
+ } else if (bestTarget === null) {
821
+ // 如果没有目标,清除防抖状态
822
+ this.targetChangeTime = null;
823
+ this.pendingTarget = null;
753
824
  }
754
825
 
755
826
  // 使用已稳定的目标进行交换
756
827
  bestTarget = this.lastBestTarget;
757
828
 
758
- // 控制交换频率,不要太高,但也不要太慢
829
+ // 控制交换频率,改为250ms,大幅增加稳定性
759
830
  const now = Date.now();
760
- if (now - this.lastSwapTime < 150 || bestTarget === null) return;
831
+ if (now - this.lastSwapTime < 250 || bestTarget === null) return;
761
832
 
762
833
  // 执行交换逻辑
763
834
  if (bestTarget !== this.draggingIndex) {
835
+ console.log(`交换元素: ${this.draggingIndex} 和 ${bestTarget}`);
836
+
837
+ // 使用ES6解构直接交换数组元素
764
838
  [
765
839
  this.processedList[this.draggingIndex],
766
840
  this.processedList[bestTarget],
@@ -768,16 +842,13 @@ export default {
768
842
  this.processedList[bestTarget],
769
843
  this.processedList[this.draggingIndex],
770
844
  ];
845
+
846
+ // 同时更新原始数据,保持同步
771
847
  [this.data.list[this.draggingIndex], this.data.list[bestTarget]] = [
772
848
  this.data.list[bestTarget],
773
849
  this.data.list[this.draggingIndex],
774
850
  ];
775
851
 
776
- console.log(this.data.list, 'cdj------this.data.list');
777
-
778
- // 更新processedList以触发视图更新和动画效果
779
- this.processedList = this.generateDataList();
780
-
781
852
  // 更新拖拽索引
782
853
  this.draggingIndex = bestTarget;
783
854
  this.lastSwapTime = now;
@@ -787,7 +858,7 @@ export default {
787
858
  // 新增:平滑更新拖拽位置的方法
788
859
  updateDragPosition() {
789
860
  // 计算当前位置到目标位置的平滑过渡
790
- const easing = 0.8; // 大幅提高缓动系数,让拖拽更紧跟手指
861
+ const easing = 0.6; // 增加缓动系数,让拖拽更跟手
791
862
 
792
863
  this.dragCloneX +=
793
864
  (this.targetTouchX - this.touchOffsetX - this.dragCloneX) * easing;
@@ -812,74 +883,58 @@ export default {
812
883
 
813
884
  // 元素本身的触摸结束
814
885
  endTouch(e) {
815
- console.log('cdj------触摸结束');
886
+ console.log('触摸结束');
816
887
  this.$emit('onDragEventEnd', e);
817
888
  // 如果只是短按(还在计时),就取消长按
818
889
  this.cancelLongPress();
819
890
 
820
891
  // 如果正在拖拽中,确保清理状态
821
892
  if (this.isTouchDragging) {
822
- // 取消动画帧
823
- if (this.animationFrameId) {
824
- cancelAnimationFrame(this.animationFrameId);
825
- this.animationFrameId = null;
826
- }
827
-
828
893
  // 移除全局事件监听
829
- document.removeEventListener('touchmove', this.onGlobalTouchMove, {
894
+ document.removeEventListener('touchmove', this.onTouchMove, {
830
895
  passive: false,
831
- capture: true,
832
896
  });
833
897
  document.removeEventListener('touchend', this.onTouchEnd, {
834
898
  passive: false,
835
- capture: true,
836
899
  });
837
900
 
838
- // 恢复页面滚动
839
- document.body.style.overflow = '';
840
- document.body.style.touchAction = '';
901
+ // 取消动画帧
902
+ if (this.animationFrameId) {
903
+ cancelAnimationFrame(this.animationFrameId);
904
+ this.animationFrameId = null;
905
+ }
841
906
 
842
907
  this.isTouchDragging = false;
843
908
  this.isDragClone = false;
844
909
  this.hoverIndex = null;
845
910
  this.draggingIndex = null;
846
-
847
- // 如果不再拖拽,恢复touch-action(但保持refresh隐藏,因为仍在编辑状态)
848
- const elements = this.findParentElements();
849
- if (elements.listInner) {
850
- elements.listInner.style.touchAction = this.originListInnerStyle;
851
- }
911
+ this.lastBestTarget = null;
912
+ this.targetChangeTime = null;
913
+ this.pendingTarget = null;
914
+ this.touchStartX = 0;
915
+ this.touchStartY = 0;
916
+ this.targetTouchX = 0;
917
+ this.targetTouchY = 0;
852
918
  }
853
919
  },
854
920
 
855
921
  // 触摸结束处理 - 全局事件
856
922
  onTouchEnd(e) {
857
- console.log('cdj------全局触摸结束');
858
-
859
- if (this.isTouchDragging) {
860
- // 确保阻止默认行为
861
- e.preventDefault();
862
- e.stopPropagation();
863
- }
864
- // 取消动画帧
865
- if (this.animationFrameId) {
866
- cancelAnimationFrame(this.animationFrameId);
867
- this.animationFrameId = null;
868
- }
923
+ console.log('全局触摸结束');
869
924
 
870
925
  // 移除全局事件监听
871
- document.removeEventListener('touchmove', this.onGlobalTouchMove, {
926
+ document.removeEventListener('touchmove', this.onTouchMove, {
872
927
  passive: false,
873
- capture: true,
874
928
  });
875
929
  document.removeEventListener('touchend', this.onTouchEnd, {
876
930
  passive: false,
877
- capture: true,
878
931
  });
879
932
 
880
- // 恢复页面滚动
881
- document.body.style.overflow = '';
882
- document.body.style.touchAction = '';
933
+ // 取消动画帧
934
+ if (this.animationFrameId) {
935
+ cancelAnimationFrame(this.animationFrameId);
936
+ this.animationFrameId = null;
937
+ }
883
938
 
884
939
  // 重置拖拽状态
885
940
  this.isTouchDragging = false;
@@ -897,6 +952,7 @@ export default {
897
952
  if (gridBoxes && gridBoxes.length > 0) {
898
953
  const box = gridBoxes[0];
899
954
  this.gridBoxWidth = box.offsetWidth;
955
+ console.log('Grid box宽度:', this.gridBoxWidth);
900
956
 
901
957
  // 更新text样式,确保不超出
902
958
  const textElements = document.querySelectorAll('.itemText');
@@ -909,14 +965,15 @@ export default {
909
965
 
910
966
  initLottieAnimations() {
911
967
  this.$nextTick(() => {
968
+ // 清理之前的动画实例
912
969
  Object.keys(this.lottieAnimations).forEach((key) => {
913
970
  const anim = this.lottieAnimations[key];
914
971
  if (anim && typeof anim.destroy === 'function') {
915
- console.log(`cdj------销毁旧动画实例: ${key}`);
972
+ console.log(`销毁旧动画实例: ${key}`);
916
973
  try {
917
974
  anim.removeEventListener('complete');
918
975
  } catch (e) {
919
- console.warn(`cdj------移除事件监听器失败: ${e.message}`);
976
+ console.warn(`移除事件监听器失败: ${e.message}`);
920
977
  }
921
978
  anim.destroy();
922
979
  }
@@ -927,155 +984,166 @@ export default {
927
984
  this.lottieAnimations = {};
928
985
 
929
986
  console.log(
930
- 'cdj------开始初始化Lottie动画,列表项数量:',
987
+ '开始初始化Lottie动画,列表项数量:',
931
988
  this.processedList.length
932
989
  );
933
990
 
934
- // 为每个列表项初始化动画
935
- this.processedList.forEach((item) => {
936
- const itemId = String(item.itemView.id);
937
- // 加载背景动画
938
- if (item.bgAnimView && item.bgAnimView.animUrl) {
991
+ // 延迟一点时间确保DOM完全更新并且之前的动画已被销毁
992
+ setTimeout(() => {
993
+ // 为每个列表项初始化动画
994
+ this.processedList.forEach((item) => {
995
+ const itemId = String(item.itemView.id);
996
+ console.log('处理项目ID:', itemId);
997
+ console.log('loadingAnimView:', item.loadingAnimView);
998
+ console.log('bgAnimView:', item.bgAnimView);
999
+ console.log('frontAnimView:', item.frontAnimView);
1000
+
1001
+ // 加载背景动画
939
1002
  this.loadLottieAnimation(
940
1003
  item.bgAnimView,
941
1004
  `bgAnim-${itemId}`,
942
1005
  `bg-${itemId}`,
943
1006
  item
944
1007
  );
945
- }
946
1008
 
947
- // 加载加载中动画
948
- if (item.loadingAnimView && item.loadingAnimView.animUrl) {
1009
+ // 加载加载中动画
949
1010
  this.loadLottieAnimation(
950
1011
  item.loadingAnimView,
951
1012
  `loadingAnim-${itemId}`,
952
1013
  `loading-${itemId}`,
953
1014
  item
954
1015
  );
955
- }
956
1016
 
957
- // 加载前景动画
958
- if (item.frontAnimView && item.frontAnimView.animUrl) {
1017
+ // 加载前景动画
959
1018
  this.loadLottieAnimation(
960
1019
  item.frontAnimView,
961
1020
  `frontAnim-${itemId}`,
962
1021
  `front-${itemId}`,
963
1022
  item
964
1023
  );
965
- }
966
- });
1024
+ });
1025
+ }, 50); // 小延迟确保DOM已更新和旧动画已销毁
967
1026
  });
968
1027
  },
969
1028
 
970
1029
  // 抽取公共的loadLottieAnimation方法
971
- loadLottieAnimation(animView, refName, animKey, item, dataIndex) {
1030
+ loadLottieAnimation(animView, refName, animKey, item) {
972
1031
  if (!animView || !animView.animUrl) {
1032
+ console.log(`[${animKey}] 跳过加载:animUrl不存在`);
973
1033
  return;
974
1034
  }
975
1035
 
1036
+ console.log(
1037
+ `[${animKey}] 尝试初始化${refName}, animUrl:`,
1038
+ animView.animUrl
1039
+ );
1040
+
976
1041
  const animEl = this.$refs[refName];
977
1042
  if (!animEl || !animEl[0]) {
1043
+ console.warn(`[${animKey}] 未找到${refName}的DOM引用`);
978
1044
  return;
979
1045
  }
980
1046
 
981
1047
  try {
982
- // 如果已经有实例,先销毁它
1048
+ // 如果已经有实例,先暂停它
983
1049
  if (this.lottieAnimations[animKey]) {
984
- this.lottieAnimations[animKey].destroy();
985
- delete this.lottieAnimations[animKey];
1050
+ this.lottieAnimations[animKey].pause();
986
1051
  }
987
1052
 
988
- // 确保animView.visibility不为0才初始化动画
1053
+ // 确保容器可见且透明度重置
1054
+ animEl[0].style.display = '';
1055
+ animEl[0].style.opacity = '1';
1056
+ animEl[0].style.transition = 'opacity 0.2s';
1057
+
989
1058
  if (
990
1059
  typeof animView.visibility !== 'number' ||
991
1060
  animView.visibility !== 0
992
1061
  ) {
993
- if (this.lottieAnimations[animKey]) {
994
- this.lottieAnimations[animKey].destroy();
995
- delete this.lottieAnimations[animKey];
996
- }
997
-
998
- // 创建新的动画实例
999
- const anim = lottie.loadAnimation({
1000
- container: animEl[0],
1001
- renderer: 'svg',
1002
- loop: Boolean(item.animRepeatCount) || false,
1003
- autoplay: true,
1004
- path: animView.animUrl,
1005
- rendererSettings: {
1006
- preserveAspectRatio: 'xMidYMid slice',
1007
- },
1008
- });
1009
-
1010
- // 保存动画实例
1011
- this.lottieAnimations[animKey] = anim;
1012
-
1013
- // 添加动画事件监听
1014
- anim.addEventListener('complete', () => {
1015
- // 检查是否需要销毁动画(非循环动画完成后销毁)
1016
- if (!item.animRepeatCount) {
1017
- // 销毁前再次检查实例是否存在
1018
- if (this.lottieAnimations[animKey] === anim) {
1019
- // 移除所有事件监听器
1020
- anim.removeEventListener('complete');
1021
- // 销毁动画实例
1022
- anim.destroy();
1023
- delete this.lottieAnimations[animKey];
1024
-
1025
- // 查找并清空对应的动画容器,彻底移除所有内容
1026
- this.$nextTick(() => {
1027
- const animContainer =
1028
- this.$refs[refName] && this.$refs[refName][0];
1029
- if (animContainer) {
1030
- // 隐藏容器
1031
- animContainer.style.display = 'none';
1032
- // 清空容器内容,确保不显示最后一帧
1033
- animContainer.innerHTML = '';
1034
- // 确保不会阻止触摸事件
1035
- animContainer.style.pointerEvents = 'none';
1036
- }
1062
+ // 延迟一帧再销毁旧实例
1063
+ requestAnimationFrame(() => {
1064
+ if (this.lottieAnimations[animKey]) {
1065
+ this.lottieAnimations[animKey].destroy();
1066
+ delete this.lottieAnimations[animKey];
1067
+ }
1037
1068
 
1038
- if (animKey.startsWith('bg-') && !item.animRepeatCount) {
1039
- this.data.list[dataIndex].bgAnimView = {
1040
- ...item.bgAnimView,
1041
- animUrl: '',
1042
- visibility: 0,
1043
- };
1044
- this.processedList[dataIndex].bgAnimView = {
1045
- ...item.bgAnimView,
1046
- animUrl: '',
1047
- visibility: 0,
1048
- };
1049
- } else if (animKey.startsWith('loading-') && !item.animRepeatCount) {
1050
- this.data.list[dataIndex].loadingAnimView = {
1051
- ...item.loadingAnimView,
1052
- animUrl: '',
1053
- visibility: 0,
1054
- };
1055
- this.processedList[dataIndex].loadingAnimView = {
1056
- ...item.loadingAnimView,
1057
- animUrl: '',
1058
- visibility: 0,
1059
- };
1060
- } else if (animKey.startsWith('front-') && !item.animRepeatCount) {
1061
- this.data.list[dataIndex].frontAnimView = {
1062
- ...item.frontAnimView,
1063
- animUrl: '',
1064
- visibility: 0,
1065
- };
1066
- this.processedList[dataIndex].frontAnimView = {
1067
- ...item.frontAnimView,
1068
- animUrl: '',
1069
- visibility: 0,
1070
- };
1069
+ // 创建新的动画实例
1070
+ console.log(`[${animKey}] 创建新的动画实例`);
1071
+ const anim = lottie.loadAnimation({
1072
+ container: animEl[0],
1073
+ renderer: 'svg',
1074
+ loop: Boolean(item.animRepeatCount) || false,
1075
+ autoplay: true,
1076
+ path: animView.animUrl,
1077
+ rendererSettings: {
1078
+ preserveAspectRatio: 'xMidYMid slice',
1079
+ progressiveLoad: true, // 启用渐进式加载
1080
+ hideOnTransparent: true, // 优化透明度处理
1081
+ },
1082
+ });
1083
+
1084
+ this.lottieAnimations[animKey] = anim;
1085
+ anim.addEventListener('complete', () => {
1086
+ // 检查是否需要销毁动画(非循环动画完成后销毁)
1087
+ if (!item.animRepeatCount) {
1088
+ // 销毁前再次检查实例是否存在
1089
+ if (this.lottieAnimations[animKey] === anim) {
1090
+ anim.removeEventListener('complete');
1091
+ anim.destroy();
1092
+ delete this.lottieAnimations[animKey];
1093
+ // 将对应数据中的animUrl清空
1094
+ const itemId = String(item.itemView.id);
1095
+ const index = this.processedList.findIndex(
1096
+ (i) => i.itemView.id == itemId
1097
+ );
1098
+ if (index !== -1) {
1099
+ // 根据动画类型设置对应的animUrl为空
1100
+ if (animKey.startsWith('bg-')) {
1101
+ this.$set(
1102
+ this.processedList[index].bgAnimView,
1103
+ 'animUrl',
1104
+ ''
1105
+ );
1106
+ this.$set(
1107
+ this.data.list[index].bgAnimView,
1108
+ 'animUrl',
1109
+ ''
1110
+ );
1111
+ } else if (animKey.startsWith('loading-')) {
1112
+ this.$set(
1113
+ this.processedList[index].loadingAnimView,
1114
+ 'animUrl',
1115
+ ''
1116
+ );
1117
+ this.$set(
1118
+ this.data.list[index].loadingAnimView,
1119
+ 'animUrl',
1120
+ ''
1121
+ );
1122
+ } else if (animKey.startsWith('front-')) {
1123
+ this.$set(
1124
+ this.processedList[index].frontAnimView,
1125
+ 'animUrl',
1126
+ ''
1127
+ );
1128
+ this.$set(
1129
+ this.data.list[index].frontAnimView,
1130
+ 'animUrl',
1131
+ ''
1132
+ );
1133
+ }
1134
+ console.log(`[${animKey}] 已清空动画URL数据`);
1135
+ item.addEventListener('touchstart', (e) => this.startLongPress(e, index), { passive: false });
1136
+ item.addEventListener('touchmove', this.checkLongPressMove, { passive: false });
1137
+ item.addEventListener('touchend', this.endTouch, { passive: false });
1138
+ item.addEventListener('touchcancel', this.endTouch, { passive: false });
1071
1139
  }
1072
- });
1140
+ }
1073
1141
  }
1074
- }
1142
+ });
1075
1143
  });
1076
1144
  }
1077
1145
  } catch (error) {
1078
- console.error('加载Lottie动画失败:', error);
1146
+ console.error(`[${animKey}] 初始化失败:`, error);
1079
1147
  }
1080
1148
  },
1081
1149
 
@@ -1090,35 +1158,66 @@ export default {
1090
1158
  }
1091
1159
  });
1092
1160
  },
1093
- // 查找父级元素和refresh元素
1094
- findParentElements() {
1095
- // 返回存储的元素引用
1096
- return {
1097
- listInner: this.weexListInnerEl,
1098
- refresh: this.weexRefreshEl,
1099
- };
1161
+
1162
+ // 暂未使用,但保留用于将来扩展
1163
+ leftTopIconClick(e) {
1164
+ e.preventDefault();
1165
+ e.stopPropagation();
1166
+ // 这里可以添加将来的处理逻辑
1167
+ return false;
1100
1168
  },
1101
1169
  },
1102
1170
  watch: {
1171
+ // 监听初始数据变化
1172
+ initialItems: {
1173
+ handler(newItems) {
1174
+ if (!this.isTouchDragging) {
1175
+ this.items = [...newItems];
1176
+ }
1177
+ },
1178
+ deep: true,
1179
+ },
1103
1180
  // 监听列表数据变化,自动更新处理后的数据
1104
1181
  'data.list': {
1105
1182
  handler(newList, oldList) {
1106
1183
  this.processedList = this.generateDataList();
1107
- console.log(newList, this.processedList, 'cdj------数据变化');
1108
1184
  this.$nextTick(() => {
1109
- this.updateGridBoxWidth();
1110
- this.updateFixedItemSize();
1185
+ // 再次使用 nextTick 确保 DOM 完全更新
1186
+ this.$nextTick(() => {
1187
+ const gridItems = document.querySelectorAll('.grid-item');
1188
+ gridItems.forEach((item, index) => {
1189
+ const hasEvents = item._vei;
1190
+ if (!hasEvents) {
1191
+ item.addEventListener('touchstart', (e) => this.startLongPress(e, index), { passive: false });
1192
+ item.addEventListener('touchmove', this.checkLongPressMove, { passive: false });
1193
+ item.addEventListener('touchend', this.endTouch, { passive: false });
1194
+ item.addEventListener('touchcancel', this.endTouch, { passive: false });
1195
+ }
1196
+ });
1197
+ this.initLottieAnimations();
1198
+ });
1111
1199
  });
1112
1200
  },
1113
1201
  deep: true,
1114
1202
  },
1203
+ // 监听所有动画URL变化,确保能及时更新动画
1204
+ processedList: {
1205
+ handler(newList, oldList) {
1206
+ if (!newList || !newList.length || this.isTouchDragging) return;
1207
+ // 避免在拖拽过程中重新初始化动画
1208
+ if (this.draggingIndex !== null) return;
1209
+ // 检查每个项目的动画URL是否有变化
1210
+ },
1211
+ deep: true,
1212
+ },
1115
1213
  },
1116
1214
  mounted() {
1117
- console.log(this.data, 'cdj------djdjdjdjdjdjdj');
1215
+ console.log(this.data, 'djdjdjdjdjdjdj');
1118
1216
  // 初始获取grid-box宽度
1119
1217
  this.updateGridBoxWidth();
1120
1218
  // 获取并存储固定宽高
1121
1219
  this.updateFixedItemSize();
1220
+
1122
1221
  // 监听窗口大小变化,更新grid-box宽度
1123
1222
  window.addEventListener('resize', () => {
1124
1223
  this.updateGridBoxWidth();
@@ -1137,19 +1236,6 @@ export default {
1137
1236
  document.removeEventListener('touchend', this.onTouchEnd, {
1138
1237
  passive: false,
1139
1238
  });
1140
- // 确保全局事件监听也被清理
1141
- document.removeEventListener('touchmove', this.onGlobalTouchMove, {
1142
- passive: false,
1143
- capture: true,
1144
- });
1145
- document.removeEventListener('touchend', this.onTouchEnd, {
1146
- passive: false,
1147
- capture: true,
1148
- });
1149
- // 恢复页面滚动状态
1150
- document.body.style.overflow = '';
1151
- document.body.style.touchAction = '';
1152
-
1153
1239
  window.removeEventListener('resize', () => {
1154
1240
  this.updateGridBoxWidth();
1155
1241
  this.updateFixedItemSize();
@@ -1165,27 +1251,19 @@ export default {
1165
1251
  Object.keys(this.lottieAnimations).forEach((key) => {
1166
1252
  const anim = this.lottieAnimations[key];
1167
1253
  if (anim && typeof anim.destroy === 'function') {
1254
+ console.log(`组件销毁时清理动画: ${key}`);
1168
1255
  try {
1169
1256
  anim.removeEventListener('complete');
1257
+ anim.removeEventListener('DOMLoaded');
1258
+ anim.removeEventListener('data_ready');
1259
+ anim.removeEventListener('loaded_images');
1260
+ anim.removeEventListener('loopComplete');
1170
1261
  } catch (e) {
1171
1262
  console.warn(`移除事件监听器失败: ${e.message}`);
1172
1263
  }
1173
1264
  anim.destroy();
1174
1265
  }
1175
1266
  delete this.lottieAnimations[key];
1176
-
1177
- // 尝试清理对应的DOM容器
1178
- const parts = key.split('-');
1179
- if (parts.length === 2) {
1180
- const animType = parts[0]; // bg, loading, front
1181
- const itemId = parts[1];
1182
- const refName = `${animType}Anim-${itemId}`;
1183
- const animContainer = this.$refs[refName] && this.$refs[refName][0];
1184
- if (animContainer) {
1185
- animContainer.innerHTML = '';
1186
- animContainer.style.display = 'none';
1187
- }
1188
- }
1189
1267
  });
1190
1268
 
1191
1269
  // 确保动画实例对象被清空
@@ -1211,6 +1289,10 @@ button {
1211
1289
  position: relative;
1212
1290
  }
1213
1291
 
1292
+ .items-container {
1293
+ width: 100%;
1294
+ }
1295
+
1214
1296
  .grid-items-wrapper {
1215
1297
  width: 100%;
1216
1298
  position: relative;
@@ -1220,15 +1302,13 @@ button {
1220
1302
  display: grid;
1221
1303
  grid-template-columns: repeat(var(--grid-cols), 1fr);
1222
1304
  grid-gap: var(--grid-gap);
1223
- width: calc(100% - var(--grid-margin));
1305
+ width: calc(100% - 74px);
1224
1306
  }
1225
1307
 
1226
1308
  /* 优化排序过渡效果 */
1227
1309
  .grid-fade-move {
1228
- transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1);
1310
+ transition: transform 0.2s cubic-bezier(0.2, 0, 0.2, 1);
1229
1311
  will-change: transform;
1230
- position: relative;
1231
- z-index: 2;
1232
1312
  }
1233
1313
 
1234
1314
  .grid-item {
@@ -1268,9 +1348,7 @@ button {
1268
1348
  top: 0;
1269
1349
  pointer-events: none;
1270
1350
  }
1271
- .lottie-container >>> * {
1272
- pointer-events: none;
1273
- }
1351
+
1274
1352
  .bg-anim,
1275
1353
  .front-anim {
1276
1354
  z-index: 1;