Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 框架

  • core模块

  • dom模块

  • control

  • geometry

  • geo

  • layer

  • Map

    • Map类
    • Map类扩展方法之BoxZoom
    • Map类扩展方法之DoubleClickZoom
    • Map类扩展方法之Drag
    • Map类扩展方法之Keyboard
    • Map类扩展方法之ScrollWheelZoom
    • Map类扩展方法之TapHold
      • 概述
      • 源码分析
        • 源码实现
        • 源码详解
      • 总结
    • Map类扩展方法之TouchZoom
  • 《Leaflet源码》笔记
  • Map
东流
2025-04-07
目录

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

# 源码详解

  • 全局配置

    定义时间阈值,然后通过Map.mergeOptions合并配置项到地图选项中,由配置可知只有在 Safari 移动浏览器上才会实例化TabHold类

  • TapHold处理器 继承自 Leaflet 的Handle基类,用于扩展地图的交互功能

  • 事件绑定与解绑

    • addHooks:在地图容器上绑定touchstart事件,当用户开始触摸时触发_onDown方法
    • removeHooks:移除touchstart事件绑定
  • 触摸开始处理(_onDown)

    • 启动定时器,若600ms内微取消且移动未超出容差,则模拟contextmenu事件
    • 阻止touchend的默认行为,避免触发点击事件
  • 取消处理(_cancel) 在触摸结束、取消或移动时,清除定时器并解绑事件

  • 触摸移动处理(_onMove) 实时记录触摸点位置,用于后续判断是否超出容差。

  • 有效性检查(_isTapValid) 计算触摸点的移动距离,与容差进行比较,若小于等于15px,则被视为有效长按。

  • 模拟事件(_simulateEvent) 创建并派发模拟的鼠标事件(如contextmenu),触发关联的右键菜单逻辑

  • 取消阻止默认行为 在长按结束后,解绑touchend的默认行为阻止,避免影响后续交互

  • 注册处理器 将TapHold处理器添加到地图初始化流程中,使其生效

# 总结

  1. 长按识别:用户触摸地图600ms且未移动超过 15px 时,触发长按。
  2. ​ 模拟右键 ​​:通过派发 contextmenu 事件,显示浏览器或地图的上下文菜单。
  3. 兼容处理 ​​:针对 Safari 移动端的触摸事件特性,手动模拟右键行为,弥补默认支持的缺失。

该模块在移动端实现了类似桌面端右键长按的效果,增强地图交互体验。

编辑 (opens new window)
上次更新: 2025/04/17, 02:36:24
Map类扩展方法之ScrollWheelZoom
Map类扩展方法之TouchZoom

← Map类扩展方法之ScrollWheelZoom Map类扩展方法之TouchZoom→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式