customer-chat-sdk 1.1.11 → 1.1.12
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/dist/core/IconManager.d.ts +11 -0
- package/dist/core/IconManager.d.ts.map +1 -1
- package/dist/customer-sdk.cjs.js +182 -11
- package/dist/customer-sdk.esm.js +182 -11
- package/dist/customer-sdk.min.js +2 -2
- package/package.json +1 -1
|
@@ -34,6 +34,8 @@ export declare class IconManager {
|
|
|
34
34
|
private iframeUpdateInterval;
|
|
35
35
|
private rafId;
|
|
36
36
|
private pendingPosition;
|
|
37
|
+
private activeDetectionRafId;
|
|
38
|
+
private lastMousePosition;
|
|
37
39
|
private onDragHandler;
|
|
38
40
|
private stopDragHandler;
|
|
39
41
|
private startDragHandler;
|
|
@@ -98,6 +100,15 @@ export declare class IconManager {
|
|
|
98
100
|
* 停止拖动
|
|
99
101
|
*/
|
|
100
102
|
private stopDrag;
|
|
103
|
+
/**
|
|
104
|
+
* 启动主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置
|
|
105
|
+
* 即使没有 mousemove 事件,也能检测到鼠标是否进入 iframe
|
|
106
|
+
*/
|
|
107
|
+
private startActiveDetection;
|
|
108
|
+
/**
|
|
109
|
+
* 停止主动检测机制
|
|
110
|
+
*/
|
|
111
|
+
private stopActiveDetection;
|
|
101
112
|
/**
|
|
102
113
|
* 清理拖动事件
|
|
103
114
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconManager.d.ts","sourceRoot":"","sources":["../../src/core/IconManager.ts"],"names":[],"mappings":"AAGA,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,UAAU,YAAY;IACpB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CACpB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,oBAAoB,CAAqC;IACjE,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,MAAM,CAAoC;IAGlD,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,cAAc,CAAK;IAG3B,OAAO,CAAC,eAAe,CAA2B;IAClD,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,uBAAuB,CAAI;IACnC,OAAO,CAAC,uBAAuB,CAAM;IAGrC,OAAO,CAAC,aAAa,CAA2D;IAChF,OAAO,CAAC,oBAAoB,CAAI;IAChC,OAAO,CAAC,oBAAoB,CAAK;IAGjC,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,eAAe,CAAqC;IAG5D,OAAO,CAAC,aAAa,CAAsD;IAC3E,OAAO,CAAC,eAAe,CAAsD;IAC7E,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,mBAAmB,CAA2C;IACtE,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,aAAa,CAAsB;gBAE/B,QAAQ,CAAC,EAAE,YAAY,EAAE,KAAK,GAAE,OAAe,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM;IAQ1F;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwH3B;;OAEG;IACH,sBAAsB,IAAI,IAAI;IAI9B;;OAEG;IACH,IAAI,IAAI,IAAI;IAoCZ;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI;IAIhC;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAqB7C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI;IAI1B;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAInC;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAInD;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IA8BpD;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAUzB;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,SAAS;
|
|
1
|
+
{"version":3,"file":"IconManager.d.ts","sourceRoot":"","sources":["../../src/core/IconManager.ts"],"names":[],"mappings":"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"}
|
package/dist/customer-sdk.cjs.js
CHANGED
|
@@ -31,10 +31,13 @@ class IconManager {
|
|
|
31
31
|
// 性能优化:缓存所有 iframe 的位置信息(用于检测鼠标是否在 iframe 上)
|
|
32
32
|
this.cachedIframes = [];
|
|
33
33
|
this.lastIframeUpdateTime = 0;
|
|
34
|
-
this.iframeUpdateInterval =
|
|
34
|
+
this.iframeUpdateInterval = 16; // 每 16ms 更新一次 iframe 位置信息(约一帧,更频繁,因为 iframe 可能移动)
|
|
35
35
|
// 性能优化:使用 requestAnimationFrame 节流位置更新
|
|
36
36
|
this.rafId = null;
|
|
37
37
|
this.pendingPosition = { x: 0, y: 0, needsUpdate: false };
|
|
38
|
+
// 主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置(即使没有 mousemove 事件)
|
|
39
|
+
this.activeDetectionRafId = null;
|
|
40
|
+
this.lastMousePosition = { x: 0, y: 0, timestamp: 0 }; // 最后记录的鼠标位置和时间戳
|
|
38
41
|
// 事件处理器引用(用于清理)
|
|
39
42
|
this.onDragHandler = null;
|
|
40
43
|
this.stopDragHandler = null;
|
|
@@ -342,6 +345,18 @@ class IconManager {
|
|
|
342
345
|
rect: iframe.getBoundingClientRect()
|
|
343
346
|
}));
|
|
344
347
|
this.lastIframeUpdateTime = Date.now();
|
|
348
|
+
if (this.debug) {
|
|
349
|
+
console.log(`[IconManager] Drag start - Found ${this.cachedIframes.length} iframe(s)`, {
|
|
350
|
+
iframes: this.cachedIframes.map(({ rect }) => ({
|
|
351
|
+
left: rect.left,
|
|
352
|
+
top: rect.top,
|
|
353
|
+
right: rect.right,
|
|
354
|
+
bottom: rect.bottom,
|
|
355
|
+
width: rect.width,
|
|
356
|
+
height: rect.height
|
|
357
|
+
}))
|
|
358
|
+
});
|
|
359
|
+
}
|
|
345
360
|
// 添加 document 事件监听器
|
|
346
361
|
if (this.onDragHandler) {
|
|
347
362
|
document.addEventListener('mousemove', this.onDragHandler);
|
|
@@ -384,7 +399,7 @@ class IconManager {
|
|
|
384
399
|
};
|
|
385
400
|
window.addEventListener('blur', this.blurHandler);
|
|
386
401
|
// 3. 添加超时机制(如果一段时间没有收到 mousemove 事件,自动停止拖动)
|
|
387
|
-
// 优化:缩短超时时间到
|
|
402
|
+
// 优化:缩短超时时间到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
388
403
|
this.dragTimeoutId = window.setTimeout(() => {
|
|
389
404
|
if (this.isDragging) {
|
|
390
405
|
if (this.debug) {
|
|
@@ -392,9 +407,21 @@ class IconManager {
|
|
|
392
407
|
}
|
|
393
408
|
this.stopDrag();
|
|
394
409
|
}
|
|
395
|
-
},
|
|
410
|
+
}, 50); // 缩短到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
411
|
+
// 4. 启动主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置
|
|
412
|
+
// 即使没有 mousemove 事件,也能检测到鼠标是否进入 iframe
|
|
413
|
+
this.startActiveDetection();
|
|
396
414
|
if (this.debug) {
|
|
397
|
-
console.log('Drag start'
|
|
415
|
+
console.log('[IconManager] Drag start', {
|
|
416
|
+
startPosition: { x: clientX, y: clientY },
|
|
417
|
+
iconRect: {
|
|
418
|
+
left: iconRect.left,
|
|
419
|
+
top: iconRect.top,
|
|
420
|
+
width: iconRect.width,
|
|
421
|
+
height: iconRect.height
|
|
422
|
+
},
|
|
423
|
+
dragOffset: this.dragOffset
|
|
424
|
+
});
|
|
398
425
|
}
|
|
399
426
|
}
|
|
400
427
|
catch (error) {
|
|
@@ -422,39 +449,79 @@ class IconManager {
|
|
|
422
449
|
now - this.lastIframeUpdateTime > this.iframeUpdateInterval) {
|
|
423
450
|
// 更新 iframe 缓存
|
|
424
451
|
const allIframes = document.querySelectorAll('iframe');
|
|
452
|
+
const previousCount = this.cachedIframes.length;
|
|
425
453
|
this.cachedIframes = Array.from(allIframes).map(iframe => ({
|
|
426
454
|
element: iframe,
|
|
427
455
|
rect: iframe.getBoundingClientRect()
|
|
428
456
|
}));
|
|
429
457
|
this.lastIframeUpdateTime = now;
|
|
458
|
+
if (this.debug && this.cachedIframes.length !== previousCount) {
|
|
459
|
+
console.log(`[IconManager] Iframe cache updated - Found ${this.cachedIframes.length} iframe(s)`, {
|
|
460
|
+
iframes: this.cachedIframes.map(({ rect }) => ({
|
|
461
|
+
left: rect.left,
|
|
462
|
+
top: rect.top,
|
|
463
|
+
right: rect.right,
|
|
464
|
+
bottom: rect.bottom
|
|
465
|
+
}))
|
|
466
|
+
});
|
|
467
|
+
}
|
|
430
468
|
}
|
|
431
469
|
// 检查鼠标是否在任何 iframe 上
|
|
432
|
-
for (const { rect } of this.cachedIframes) {
|
|
470
|
+
for (const { rect, element } of this.cachedIframes) {
|
|
433
471
|
if (clientX >= rect.left &&
|
|
434
472
|
clientX <= rect.right &&
|
|
435
473
|
clientY >= rect.top &&
|
|
436
474
|
clientY <= rect.bottom) {
|
|
437
475
|
// 鼠标在 iframe 上,立即停止拖动
|
|
438
476
|
if (this.debug) {
|
|
439
|
-
console.log('Mouse over iframe, stopping drag immediately'
|
|
477
|
+
console.log('[IconManager] Mouse over iframe detected, stopping drag immediately', {
|
|
478
|
+
mousePosition: { x: clientX, y: clientY },
|
|
479
|
+
iframeRect: {
|
|
480
|
+
left: rect.left,
|
|
481
|
+
top: rect.top,
|
|
482
|
+
right: rect.right,
|
|
483
|
+
bottom: rect.bottom
|
|
484
|
+
},
|
|
485
|
+
iframeSrc: element.src || 'no src'
|
|
486
|
+
});
|
|
440
487
|
}
|
|
441
488
|
this.stopDrag();
|
|
442
489
|
return;
|
|
443
490
|
}
|
|
444
491
|
}
|
|
445
492
|
}
|
|
493
|
+
// 更新最后记录的鼠标位置和时间戳(用于主动检测)
|
|
494
|
+
const now = Date.now();
|
|
495
|
+
const timeSinceLastUpdate = now - this.lastMousePosition.timestamp;
|
|
496
|
+
this.lastMousePosition = {
|
|
497
|
+
x: clientX,
|
|
498
|
+
y: clientY,
|
|
499
|
+
timestamp: now
|
|
500
|
+
};
|
|
501
|
+
// 如果距离上次更新超过 50ms,记录警告(可能事件丢失)
|
|
502
|
+
if (this.debug && timeSinceLastUpdate > 50 && this.lastMousePosition.timestamp > 0) {
|
|
503
|
+
console.warn(`[IconManager] Long gap between mousemove events: ${timeSinceLastUpdate}ms`, {
|
|
504
|
+
lastPosition: { x: this.lastMousePosition.x, y: this.lastMousePosition.y },
|
|
505
|
+
currentPosition: { x: clientX, y: clientY }
|
|
506
|
+
});
|
|
507
|
+
}
|
|
446
508
|
// 重置超时定时器(每次移动都重置,确保只有真正停止移动时才触发超时)
|
|
447
|
-
// 优化:缩短超时时间到
|
|
509
|
+
// 优化:缩短超时时间到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
448
510
|
if (this.dragTimeoutId !== null) {
|
|
449
511
|
window.clearTimeout(this.dragTimeoutId);
|
|
450
512
|
this.dragTimeoutId = window.setTimeout(() => {
|
|
451
513
|
if (this.isDragging) {
|
|
452
514
|
if (this.debug) {
|
|
453
|
-
|
|
515
|
+
const timeSinceLastMove = Date.now() - this.lastMousePosition.timestamp;
|
|
516
|
+
console.warn('[IconManager] Drag timeout triggered, stopping drag (likely mouse moved over iframe)', {
|
|
517
|
+
timeSinceLastMove,
|
|
518
|
+
lastMousePosition: this.lastMousePosition,
|
|
519
|
+
iframeCount: this.cachedIframes.length
|
|
520
|
+
});
|
|
454
521
|
}
|
|
455
522
|
this.stopDrag();
|
|
456
523
|
}
|
|
457
|
-
},
|
|
524
|
+
}, 50); // 缩短到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
458
525
|
}
|
|
459
526
|
// 检查是否有足够的移动距离
|
|
460
527
|
const deltaX = Math.abs(clientX - this.lastTouchPosition.x);
|
|
@@ -566,6 +633,14 @@ class IconManager {
|
|
|
566
633
|
* 停止拖动
|
|
567
634
|
*/
|
|
568
635
|
stopDrag(_e) {
|
|
636
|
+
const stopReason = this.isDragging ? 'drag_stopped' : 'not_dragging';
|
|
637
|
+
const finalPosition = this.iconElement ? {
|
|
638
|
+
left: this.iconElement.style.left,
|
|
639
|
+
top: this.iconElement.style.top,
|
|
640
|
+
computed: window.getComputedStyle(this.iconElement).left !== 'auto'
|
|
641
|
+
? { left: window.getComputedStyle(this.iconElement).left, top: window.getComputedStyle(this.iconElement).top }
|
|
642
|
+
: null
|
|
643
|
+
} : null;
|
|
569
644
|
this.cleanupDragEvents();
|
|
570
645
|
if (!this.iconElement)
|
|
571
646
|
return;
|
|
@@ -576,11 +651,14 @@ class IconManager {
|
|
|
576
651
|
const touchDuration = Date.now() - this.touchStartTime;
|
|
577
652
|
const isValidClick = !this.hasMoved && touchDuration < 1000 && !this.dragStarted;
|
|
578
653
|
if (this.debug) {
|
|
579
|
-
console.log('Drag end', {
|
|
654
|
+
console.log('[IconManager] Drag end', {
|
|
655
|
+
stopReason,
|
|
580
656
|
hasMoved: this.hasMoved,
|
|
581
657
|
dragStarted: this.dragStarted,
|
|
582
658
|
touchDuration,
|
|
583
|
-
isValidClick
|
|
659
|
+
isValidClick,
|
|
660
|
+
finalPosition,
|
|
661
|
+
lastMousePosition: this.lastMousePosition
|
|
584
662
|
});
|
|
585
663
|
}
|
|
586
664
|
// 先保存点击状态,然后重置拖动状态
|
|
@@ -620,6 +698,97 @@ class IconManager {
|
|
|
620
698
|
}, 100); // 增加延迟到 100ms,确保拖动状态完全重置
|
|
621
699
|
}
|
|
622
700
|
}
|
|
701
|
+
/**
|
|
702
|
+
* 启动主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置
|
|
703
|
+
* 即使没有 mousemove 事件,也能检测到鼠标是否进入 iframe
|
|
704
|
+
*/
|
|
705
|
+
startActiveDetection() {
|
|
706
|
+
if (this.activeDetectionRafId !== null) {
|
|
707
|
+
if (this.debug) {
|
|
708
|
+
console.log('[IconManager] Active detection already running');
|
|
709
|
+
}
|
|
710
|
+
return; // 已经在运行
|
|
711
|
+
}
|
|
712
|
+
if (this.debug) {
|
|
713
|
+
console.log('[IconManager] Starting active detection mechanism');
|
|
714
|
+
}
|
|
715
|
+
const checkMousePosition = () => {
|
|
716
|
+
if (!this.isDragging) {
|
|
717
|
+
if (this.debug) {
|
|
718
|
+
console.log('[IconManager] Active detection stopped (drag ended)');
|
|
719
|
+
}
|
|
720
|
+
this.activeDetectionRafId = null;
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
// 检查是否长时间没有收到 mousemove 事件(超过 50ms)
|
|
724
|
+
const now = Date.now();
|
|
725
|
+
const timeSinceLastMove = now - this.lastMousePosition.timestamp;
|
|
726
|
+
if (timeSinceLastMove > 50) {
|
|
727
|
+
// 长时间没有收到事件,可能鼠标已经进入 iframe
|
|
728
|
+
// 使用最后记录的鼠标位置进行检测
|
|
729
|
+
const clientX = this.lastMousePosition.x;
|
|
730
|
+
const clientY = this.lastMousePosition.y;
|
|
731
|
+
if (this.debug) {
|
|
732
|
+
console.log(`[IconManager] Active detection: No mousemove event for ${timeSinceLastMove}ms`, {
|
|
733
|
+
lastMousePosition: { x: clientX, y: clientY },
|
|
734
|
+
timestamp: this.lastMousePosition.timestamp
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
// 更新 iframe 缓存(更频繁,每帧更新)
|
|
738
|
+
if (this.cachedIframes.length === 0 ||
|
|
739
|
+
now - this.lastIframeUpdateTime > this.iframeUpdateInterval) {
|
|
740
|
+
const allIframes = document.querySelectorAll('iframe');
|
|
741
|
+
this.cachedIframes = Array.from(allIframes).map(iframe => ({
|
|
742
|
+
element: iframe,
|
|
743
|
+
rect: iframe.getBoundingClientRect()
|
|
744
|
+
}));
|
|
745
|
+
this.lastIframeUpdateTime = now;
|
|
746
|
+
if (this.debug) {
|
|
747
|
+
console.log(`[IconManager] Active detection: Updated iframe cache (${this.cachedIframes.length} iframes)`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
// 检查最后记录的鼠标位置是否在任何 iframe 上
|
|
751
|
+
for (const { rect, element } of this.cachedIframes) {
|
|
752
|
+
if (clientX >= rect.left &&
|
|
753
|
+
clientX <= rect.right &&
|
|
754
|
+
clientY >= rect.top &&
|
|
755
|
+
clientY <= rect.bottom) {
|
|
756
|
+
// 鼠标在 iframe 上,立即停止拖动
|
|
757
|
+
if (this.debug) {
|
|
758
|
+
console.log('[IconManager] Active detection: Mouse over iframe detected, stopping drag immediately', {
|
|
759
|
+
mousePosition: { x: clientX, y: clientY },
|
|
760
|
+
iframeRect: {
|
|
761
|
+
left: rect.left,
|
|
762
|
+
top: rect.top,
|
|
763
|
+
right: rect.right,
|
|
764
|
+
bottom: rect.bottom
|
|
765
|
+
},
|
|
766
|
+
iframeSrc: element.src || 'no src',
|
|
767
|
+
timeSinceLastMove
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
this.stopDrag();
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
// 继续检测
|
|
776
|
+
this.activeDetectionRafId = requestAnimationFrame(checkMousePosition);
|
|
777
|
+
};
|
|
778
|
+
this.activeDetectionRafId = requestAnimationFrame(checkMousePosition);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* 停止主动检测机制
|
|
782
|
+
*/
|
|
783
|
+
stopActiveDetection() {
|
|
784
|
+
if (this.activeDetectionRafId !== null) {
|
|
785
|
+
if (this.debug) {
|
|
786
|
+
console.log('[IconManager] Stopping active detection mechanism');
|
|
787
|
+
}
|
|
788
|
+
cancelAnimationFrame(this.activeDetectionRafId);
|
|
789
|
+
this.activeDetectionRafId = null;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
623
792
|
/**
|
|
624
793
|
* 清理拖动事件
|
|
625
794
|
*/
|
|
@@ -656,6 +825,8 @@ class IconManager {
|
|
|
656
825
|
cancelAnimationFrame(this.rafId);
|
|
657
826
|
this.rafId = null;
|
|
658
827
|
}
|
|
828
|
+
// 清理主动检测机制
|
|
829
|
+
this.stopActiveDetection();
|
|
659
830
|
// 清理缓存
|
|
660
831
|
this.cachedContainer = null;
|
|
661
832
|
this.cachedContainerRect = null;
|
package/dist/customer-sdk.esm.js
CHANGED
|
@@ -27,10 +27,13 @@ class IconManager {
|
|
|
27
27
|
// 性能优化:缓存所有 iframe 的位置信息(用于检测鼠标是否在 iframe 上)
|
|
28
28
|
this.cachedIframes = [];
|
|
29
29
|
this.lastIframeUpdateTime = 0;
|
|
30
|
-
this.iframeUpdateInterval =
|
|
30
|
+
this.iframeUpdateInterval = 16; // 每 16ms 更新一次 iframe 位置信息(约一帧,更频繁,因为 iframe 可能移动)
|
|
31
31
|
// 性能优化:使用 requestAnimationFrame 节流位置更新
|
|
32
32
|
this.rafId = null;
|
|
33
33
|
this.pendingPosition = { x: 0, y: 0, needsUpdate: false };
|
|
34
|
+
// 主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置(即使没有 mousemove 事件)
|
|
35
|
+
this.activeDetectionRafId = null;
|
|
36
|
+
this.lastMousePosition = { x: 0, y: 0, timestamp: 0 }; // 最后记录的鼠标位置和时间戳
|
|
34
37
|
// 事件处理器引用(用于清理)
|
|
35
38
|
this.onDragHandler = null;
|
|
36
39
|
this.stopDragHandler = null;
|
|
@@ -338,6 +341,18 @@ class IconManager {
|
|
|
338
341
|
rect: iframe.getBoundingClientRect()
|
|
339
342
|
}));
|
|
340
343
|
this.lastIframeUpdateTime = Date.now();
|
|
344
|
+
if (this.debug) {
|
|
345
|
+
console.log(`[IconManager] Drag start - Found ${this.cachedIframes.length} iframe(s)`, {
|
|
346
|
+
iframes: this.cachedIframes.map(({ rect }) => ({
|
|
347
|
+
left: rect.left,
|
|
348
|
+
top: rect.top,
|
|
349
|
+
right: rect.right,
|
|
350
|
+
bottom: rect.bottom,
|
|
351
|
+
width: rect.width,
|
|
352
|
+
height: rect.height
|
|
353
|
+
}))
|
|
354
|
+
});
|
|
355
|
+
}
|
|
341
356
|
// 添加 document 事件监听器
|
|
342
357
|
if (this.onDragHandler) {
|
|
343
358
|
document.addEventListener('mousemove', this.onDragHandler);
|
|
@@ -380,7 +395,7 @@ class IconManager {
|
|
|
380
395
|
};
|
|
381
396
|
window.addEventListener('blur', this.blurHandler);
|
|
382
397
|
// 3. 添加超时机制(如果一段时间没有收到 mousemove 事件,自动停止拖动)
|
|
383
|
-
// 优化:缩短超时时间到
|
|
398
|
+
// 优化:缩短超时时间到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
384
399
|
this.dragTimeoutId = window.setTimeout(() => {
|
|
385
400
|
if (this.isDragging) {
|
|
386
401
|
if (this.debug) {
|
|
@@ -388,9 +403,21 @@ class IconManager {
|
|
|
388
403
|
}
|
|
389
404
|
this.stopDrag();
|
|
390
405
|
}
|
|
391
|
-
},
|
|
406
|
+
}, 50); // 缩短到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
407
|
+
// 4. 启动主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置
|
|
408
|
+
// 即使没有 mousemove 事件,也能检测到鼠标是否进入 iframe
|
|
409
|
+
this.startActiveDetection();
|
|
392
410
|
if (this.debug) {
|
|
393
|
-
console.log('Drag start'
|
|
411
|
+
console.log('[IconManager] Drag start', {
|
|
412
|
+
startPosition: { x: clientX, y: clientY },
|
|
413
|
+
iconRect: {
|
|
414
|
+
left: iconRect.left,
|
|
415
|
+
top: iconRect.top,
|
|
416
|
+
width: iconRect.width,
|
|
417
|
+
height: iconRect.height
|
|
418
|
+
},
|
|
419
|
+
dragOffset: this.dragOffset
|
|
420
|
+
});
|
|
394
421
|
}
|
|
395
422
|
}
|
|
396
423
|
catch (error) {
|
|
@@ -418,39 +445,79 @@ class IconManager {
|
|
|
418
445
|
now - this.lastIframeUpdateTime > this.iframeUpdateInterval) {
|
|
419
446
|
// 更新 iframe 缓存
|
|
420
447
|
const allIframes = document.querySelectorAll('iframe');
|
|
448
|
+
const previousCount = this.cachedIframes.length;
|
|
421
449
|
this.cachedIframes = Array.from(allIframes).map(iframe => ({
|
|
422
450
|
element: iframe,
|
|
423
451
|
rect: iframe.getBoundingClientRect()
|
|
424
452
|
}));
|
|
425
453
|
this.lastIframeUpdateTime = now;
|
|
454
|
+
if (this.debug && this.cachedIframes.length !== previousCount) {
|
|
455
|
+
console.log(`[IconManager] Iframe cache updated - Found ${this.cachedIframes.length} iframe(s)`, {
|
|
456
|
+
iframes: this.cachedIframes.map(({ rect }) => ({
|
|
457
|
+
left: rect.left,
|
|
458
|
+
top: rect.top,
|
|
459
|
+
right: rect.right,
|
|
460
|
+
bottom: rect.bottom
|
|
461
|
+
}))
|
|
462
|
+
});
|
|
463
|
+
}
|
|
426
464
|
}
|
|
427
465
|
// 检查鼠标是否在任何 iframe 上
|
|
428
|
-
for (const { rect } of this.cachedIframes) {
|
|
466
|
+
for (const { rect, element } of this.cachedIframes) {
|
|
429
467
|
if (clientX >= rect.left &&
|
|
430
468
|
clientX <= rect.right &&
|
|
431
469
|
clientY >= rect.top &&
|
|
432
470
|
clientY <= rect.bottom) {
|
|
433
471
|
// 鼠标在 iframe 上,立即停止拖动
|
|
434
472
|
if (this.debug) {
|
|
435
|
-
console.log('Mouse over iframe, stopping drag immediately'
|
|
473
|
+
console.log('[IconManager] Mouse over iframe detected, stopping drag immediately', {
|
|
474
|
+
mousePosition: { x: clientX, y: clientY },
|
|
475
|
+
iframeRect: {
|
|
476
|
+
left: rect.left,
|
|
477
|
+
top: rect.top,
|
|
478
|
+
right: rect.right,
|
|
479
|
+
bottom: rect.bottom
|
|
480
|
+
},
|
|
481
|
+
iframeSrc: element.src || 'no src'
|
|
482
|
+
});
|
|
436
483
|
}
|
|
437
484
|
this.stopDrag();
|
|
438
485
|
return;
|
|
439
486
|
}
|
|
440
487
|
}
|
|
441
488
|
}
|
|
489
|
+
// 更新最后记录的鼠标位置和时间戳(用于主动检测)
|
|
490
|
+
const now = Date.now();
|
|
491
|
+
const timeSinceLastUpdate = now - this.lastMousePosition.timestamp;
|
|
492
|
+
this.lastMousePosition = {
|
|
493
|
+
x: clientX,
|
|
494
|
+
y: clientY,
|
|
495
|
+
timestamp: now
|
|
496
|
+
};
|
|
497
|
+
// 如果距离上次更新超过 50ms,记录警告(可能事件丢失)
|
|
498
|
+
if (this.debug && timeSinceLastUpdate > 50 && this.lastMousePosition.timestamp > 0) {
|
|
499
|
+
console.warn(`[IconManager] Long gap between mousemove events: ${timeSinceLastUpdate}ms`, {
|
|
500
|
+
lastPosition: { x: this.lastMousePosition.x, y: this.lastMousePosition.y },
|
|
501
|
+
currentPosition: { x: clientX, y: clientY }
|
|
502
|
+
});
|
|
503
|
+
}
|
|
442
504
|
// 重置超时定时器(每次移动都重置,确保只有真正停止移动时才触发超时)
|
|
443
|
-
// 优化:缩短超时时间到
|
|
505
|
+
// 优化:缩短超时时间到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
444
506
|
if (this.dragTimeoutId !== null) {
|
|
445
507
|
window.clearTimeout(this.dragTimeoutId);
|
|
446
508
|
this.dragTimeoutId = window.setTimeout(() => {
|
|
447
509
|
if (this.isDragging) {
|
|
448
510
|
if (this.debug) {
|
|
449
|
-
|
|
511
|
+
const timeSinceLastMove = Date.now() - this.lastMousePosition.timestamp;
|
|
512
|
+
console.warn('[IconManager] Drag timeout triggered, stopping drag (likely mouse moved over iframe)', {
|
|
513
|
+
timeSinceLastMove,
|
|
514
|
+
lastMousePosition: this.lastMousePosition,
|
|
515
|
+
iframeCount: this.cachedIframes.length
|
|
516
|
+
});
|
|
450
517
|
}
|
|
451
518
|
this.stopDrag();
|
|
452
519
|
}
|
|
453
|
-
},
|
|
520
|
+
}, 50); // 缩短到 50ms,更快检测到事件丢失(特别是嵌套 iframe 场景)
|
|
454
521
|
}
|
|
455
522
|
// 检查是否有足够的移动距离
|
|
456
523
|
const deltaX = Math.abs(clientX - this.lastTouchPosition.x);
|
|
@@ -562,6 +629,14 @@ class IconManager {
|
|
|
562
629
|
* 停止拖动
|
|
563
630
|
*/
|
|
564
631
|
stopDrag(_e) {
|
|
632
|
+
const stopReason = this.isDragging ? 'drag_stopped' : 'not_dragging';
|
|
633
|
+
const finalPosition = this.iconElement ? {
|
|
634
|
+
left: this.iconElement.style.left,
|
|
635
|
+
top: this.iconElement.style.top,
|
|
636
|
+
computed: window.getComputedStyle(this.iconElement).left !== 'auto'
|
|
637
|
+
? { left: window.getComputedStyle(this.iconElement).left, top: window.getComputedStyle(this.iconElement).top }
|
|
638
|
+
: null
|
|
639
|
+
} : null;
|
|
565
640
|
this.cleanupDragEvents();
|
|
566
641
|
if (!this.iconElement)
|
|
567
642
|
return;
|
|
@@ -572,11 +647,14 @@ class IconManager {
|
|
|
572
647
|
const touchDuration = Date.now() - this.touchStartTime;
|
|
573
648
|
const isValidClick = !this.hasMoved && touchDuration < 1000 && !this.dragStarted;
|
|
574
649
|
if (this.debug) {
|
|
575
|
-
console.log('Drag end', {
|
|
650
|
+
console.log('[IconManager] Drag end', {
|
|
651
|
+
stopReason,
|
|
576
652
|
hasMoved: this.hasMoved,
|
|
577
653
|
dragStarted: this.dragStarted,
|
|
578
654
|
touchDuration,
|
|
579
|
-
isValidClick
|
|
655
|
+
isValidClick,
|
|
656
|
+
finalPosition,
|
|
657
|
+
lastMousePosition: this.lastMousePosition
|
|
580
658
|
});
|
|
581
659
|
}
|
|
582
660
|
// 先保存点击状态,然后重置拖动状态
|
|
@@ -616,6 +694,97 @@ class IconManager {
|
|
|
616
694
|
}, 100); // 增加延迟到 100ms,确保拖动状态完全重置
|
|
617
695
|
}
|
|
618
696
|
}
|
|
697
|
+
/**
|
|
698
|
+
* 启动主动检测机制:使用 requestAnimationFrame 定期检查鼠标位置
|
|
699
|
+
* 即使没有 mousemove 事件,也能检测到鼠标是否进入 iframe
|
|
700
|
+
*/
|
|
701
|
+
startActiveDetection() {
|
|
702
|
+
if (this.activeDetectionRafId !== null) {
|
|
703
|
+
if (this.debug) {
|
|
704
|
+
console.log('[IconManager] Active detection already running');
|
|
705
|
+
}
|
|
706
|
+
return; // 已经在运行
|
|
707
|
+
}
|
|
708
|
+
if (this.debug) {
|
|
709
|
+
console.log('[IconManager] Starting active detection mechanism');
|
|
710
|
+
}
|
|
711
|
+
const checkMousePosition = () => {
|
|
712
|
+
if (!this.isDragging) {
|
|
713
|
+
if (this.debug) {
|
|
714
|
+
console.log('[IconManager] Active detection stopped (drag ended)');
|
|
715
|
+
}
|
|
716
|
+
this.activeDetectionRafId = null;
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
// 检查是否长时间没有收到 mousemove 事件(超过 50ms)
|
|
720
|
+
const now = Date.now();
|
|
721
|
+
const timeSinceLastMove = now - this.lastMousePosition.timestamp;
|
|
722
|
+
if (timeSinceLastMove > 50) {
|
|
723
|
+
// 长时间没有收到事件,可能鼠标已经进入 iframe
|
|
724
|
+
// 使用最后记录的鼠标位置进行检测
|
|
725
|
+
const clientX = this.lastMousePosition.x;
|
|
726
|
+
const clientY = this.lastMousePosition.y;
|
|
727
|
+
if (this.debug) {
|
|
728
|
+
console.log(`[IconManager] Active detection: No mousemove event for ${timeSinceLastMove}ms`, {
|
|
729
|
+
lastMousePosition: { x: clientX, y: clientY },
|
|
730
|
+
timestamp: this.lastMousePosition.timestamp
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
// 更新 iframe 缓存(更频繁,每帧更新)
|
|
734
|
+
if (this.cachedIframes.length === 0 ||
|
|
735
|
+
now - this.lastIframeUpdateTime > this.iframeUpdateInterval) {
|
|
736
|
+
const allIframes = document.querySelectorAll('iframe');
|
|
737
|
+
this.cachedIframes = Array.from(allIframes).map(iframe => ({
|
|
738
|
+
element: iframe,
|
|
739
|
+
rect: iframe.getBoundingClientRect()
|
|
740
|
+
}));
|
|
741
|
+
this.lastIframeUpdateTime = now;
|
|
742
|
+
if (this.debug) {
|
|
743
|
+
console.log(`[IconManager] Active detection: Updated iframe cache (${this.cachedIframes.length} iframes)`);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// 检查最后记录的鼠标位置是否在任何 iframe 上
|
|
747
|
+
for (const { rect, element } of this.cachedIframes) {
|
|
748
|
+
if (clientX >= rect.left &&
|
|
749
|
+
clientX <= rect.right &&
|
|
750
|
+
clientY >= rect.top &&
|
|
751
|
+
clientY <= rect.bottom) {
|
|
752
|
+
// 鼠标在 iframe 上,立即停止拖动
|
|
753
|
+
if (this.debug) {
|
|
754
|
+
console.log('[IconManager] Active detection: Mouse over iframe detected, stopping drag immediately', {
|
|
755
|
+
mousePosition: { x: clientX, y: clientY },
|
|
756
|
+
iframeRect: {
|
|
757
|
+
left: rect.left,
|
|
758
|
+
top: rect.top,
|
|
759
|
+
right: rect.right,
|
|
760
|
+
bottom: rect.bottom
|
|
761
|
+
},
|
|
762
|
+
iframeSrc: element.src || 'no src',
|
|
763
|
+
timeSinceLastMove
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
this.stopDrag();
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
// 继续检测
|
|
772
|
+
this.activeDetectionRafId = requestAnimationFrame(checkMousePosition);
|
|
773
|
+
};
|
|
774
|
+
this.activeDetectionRafId = requestAnimationFrame(checkMousePosition);
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* 停止主动检测机制
|
|
778
|
+
*/
|
|
779
|
+
stopActiveDetection() {
|
|
780
|
+
if (this.activeDetectionRafId !== null) {
|
|
781
|
+
if (this.debug) {
|
|
782
|
+
console.log('[IconManager] Stopping active detection mechanism');
|
|
783
|
+
}
|
|
784
|
+
cancelAnimationFrame(this.activeDetectionRafId);
|
|
785
|
+
this.activeDetectionRafId = null;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
619
788
|
/**
|
|
620
789
|
* 清理拖动事件
|
|
621
790
|
*/
|
|
@@ -652,6 +821,8 @@ class IconManager {
|
|
|
652
821
|
cancelAnimationFrame(this.rafId);
|
|
653
822
|
this.rafId = null;
|
|
654
823
|
}
|
|
824
|
+
// 清理主动检测机制
|
|
825
|
+
this.stopActiveDetection();
|
|
655
826
|
// 清理缓存
|
|
656
827
|
this.cachedContainer = null;
|
|
657
828
|
this.cachedContainerRect = null;
|