Map类扩展方法之TapHold
# 概述
TapHold
是Map
类的扩展方法,用于处理移动端长按手势的模块,主要实现在触摸设备上长安地图时触发上下文菜单(如右键菜单)的功能,具体来说在支持触摸的 Safari 移动浏览器中生效。
# 源码分析
# 源码实现
TapHold
的源码实现如下:
var tapHoldDelay = 600; //定义长按的时间阈值600ms,超过此时间视为长按
Map.mergeOptions({
tapHold: Browser.touchNative && Browser.safari && Browser.mobile, // safari 移动浏览器上支持长按功能
tapTolerance: 15, // 触摸点允许的最大移动距离 15px,超出则取消长按
});
export var TapHold = Handler.extend({
addHooks: function () {
DomEvent.on(this._map._container, "touchstart", this._onDown, this);
},
removeHooks: function () {
DomEvent.off(this._map._container, "touchstart", this._onDown, this);
},
_onDown: function (e) {
clearTimeout(this._holdTimeout);
if (e.touches.length !== 1) {
return;
} // 仅处理单指操作
// 记录触摸起点
var first = e.touches[0];
this._startPos = this._newPos = new Point(first.clientX, first.clientY);
// 设置长按定时器
this._holdTimeout = setTimeout(
Util.bind(function () {
this._cancel();
// 检查是否移动超出容差
if (!this._isTapValid()) {
return;
}
DomEvent.on(document, "touchend", DomEvent.preventDefault); // 阻止默认行为
DomEvent.on(document, "touchend touchcancel", this._cancelClickPrevent);
this._simulateEvent("contextmenu", first); // 模拟右键事件
}, this),
tapHoldDelay
);
// 绑定取消事件和移动监听
DomEvent.on(
document,
"touchend touchcancel contextmenu",
this._cancel,
this
);
DomEvent.on(document, "touchmove", this._onMove, this);
},
_cancelClickPrevent: function () {
DomEvent.off(document, "touchend", DomEvent.preventDefault);
DomEvent.off(document, "touchend touchcancel", cancelClickPrevent);
},
_cancel: function (e) {
clearTimeout(this._holdTimeout); //清除定时器
// 解绑所有文档级事件
DomEvent.off(
document,
"touchend touchcancel contextmenu",
this._cancel,
this
);
DomEvent.off(document, "touchmove", this._onMove, this);
},
_onMove: function (e) {
var first = e.touches[0];
this._newPos = new Point(first.clientX, first.clientY); //更新当前位置
},
_isTapValid: function () {
return (
this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance
);
},
_simulateEvent: function (type, e) {
var simulatedEvent = new MouseEvent(type, {
bubbles: true,
cancelable: true,
view: window,
screenX: e.screenX,
screenY: e.screenY,
clientX: e.clientX,
clientY: e.clientY,
});
simulatedEvent._simulated = true; //标记为模拟事件
e.target.dispatchEvent(simulatedEvent); // 派发到目标元素
},
});
Map.addInitHook("addHandler", "tapHold", TapHold);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 源码详解
全局配置
定义时间阈值,然后通过
Map.mergeOptions
合并配置项到地图选项中,由配置可知只有在 Safari 移动浏览器上才会实例化TabHold
类TapHold
处理器 继承自 Leaflet 的Handle
基类,用于扩展地图的交互功能事件绑定与解绑
addHooks
:在地图容器上绑定touchstart
事件,当用户开始触摸时触发_onDown
方法removeHooks
:移除touchstart
事件绑定
触摸开始处理(
_onDown
)- 启动定时器,若
600ms
内微取消且移动未超出容差,则模拟contextmenu
事件 - 阻止
touchend
的默认行为,避免触发点击事件
- 启动定时器,若
取消处理(
_cancel
) 在触摸结束、取消或移动时,清除定时器并解绑事件触摸移动处理(
_onMove
) 实时记录触摸点位置,用于后续判断是否超出容差。有效性检查(
_isTapValid
) 计算触摸点的移动距离,与容差进行比较,若小于等于15px
,则被视为有效长按。模拟事件(
_simulateEvent
) 创建并派发模拟的鼠标事件(如contextmenu
),触发关联的右键菜单逻辑取消阻止默认行为 在长按结束后,解绑
touchend
的默认行为阻止,避免影响后续交互注册处理器 将
TapHold
处理器添加到地图初始化流程中,使其生效
# 总结
- 长按识别:用户触摸地图
600ms
且未移动超过15px
时,触发长按。 - 模拟右键 :通过派发
contextmenu 事件
,显示浏览器或地图的上下文菜单。 - 兼容处理 :针对 Safari 移动端的触摸事件特性,手动模拟右键行为,弥补默认支持的缺失。
该模块在移动端实现了类似桌面端右键长按的效果,增强地图交互体验。
编辑 (opens new window)
上次更新: 2025/04/17, 02:36:24