Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 框架

  • core模块

  • dom模块

    • DomEvent
    • DomUtil
    • DomEvent.Pointer
    • DomEvent.DoubleTap
      • 概述
      • 源码分析
        • 源码实现如下
        • 源码详解
        • 关键设计思想
        • 使用场景
        • 潜在问题与注意事项
      • 总结
    • Draggable拖拽实现
    • PosAnimation位置动画介绍
  • control

  • geometry

  • geo

  • layer

  • Map

  • 《Leaflet源码》笔记
  • dom模块
东流
2025-03-20
目录

DomEvent.DoubleTap

# 概述

DomEvent.DoubleTap模块是Leaflet中用于模拟双击(dbclick)事件的模块,主要解决移动端浏览器对双击事件支持不完善或延迟的问题,同时避免与标签(<label>)关联的表单元素误触发。

# 源码分析

# 源码实现如下

DomEvent.DoubleTap的源码实现如下:

function makeDblclick(event) {
  var newEvent = {},
    prop,
    i;
  // 复制原始事件的所有属性(包括方法)  
  for (i in event) {
    prop = event[i];
    newEvent[i] = prop && prop.bind ? prop.bind(event) : prop;
  }
  event = newEvent;

  // 修改事件类型为dbclick,并标记为模拟事件
  newEvent.type = "dblclick";
  newEvent.detail = 2;//表示双击
  newEvent.isTrusted = false;//非浏览器原生触发
  newEvent._simulated = true; //Leaflet内部标记
  return newEvent;
}

var delay = 200;
export function addDoubleTapListener(obj, handler) {
  // 直接监听原生dbclick事件(桌面浏览器)
  obj.addEventListener("dblclick", handler);

  var last = 0,
    detail;
  function simDblclick(e) {
    //忽略非单次点击事件
    if (e.detail !== 1) {
      detail = e.detail;
      return;
    }

    // 过滤鼠标事件,仅处理触控或笔触
    if (
      e.pointerType === "mouse" ||
      (e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)
    ) {
      return;
    }

    // 检查事件路径,避免label元素误触发
    var path = DomEvent.getPropagationPath(e);
    if (
      path.some(function (el) {
        return el instanceof HTMLLabelElement && el.attributes.for;
      }) &&
      !path.some(function (el) {
        return (
          el instanceof HTMLInputElement || el instanceof HTMLSelectElement
        );
      })
    ) {
      return;
    }

    // 计算事件间隔,模拟双击
    var now = Date.now();
    if (now - last <= delay) {
      detail++;
      if (detail === 2) {
        handler(makeDblclick(e)); //触发自定义dbclick事件
      }
    } else {
      detail = 1;
    }
    last = now;
  }
  
  // 监听click事件,通过时间间隔判断双击
  obj.addEventListener("click", simDblclick);

  return {
    dblclick: handler,
    simDblclick: simDblclick,
  };
}

export function removeDoubleTapListener(obj, handlers) {
  obj.removeEventListener("dblclick", handlers.dblclick);
  obj.removeEventListener("click", handlers.simDblclick);
}
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

# 源码详解

  1. makeDbclick(event)函数:构造模拟的双击事件:
  • ​目的:克隆原始事件并转换为自定义的 dblclick 事件,用于模拟双击行为。
  • 关键点:
    • ​属性复制:遍历原始事件属性,若属性是方法(如 preventDefault),则绑定到原始事件上下文。
    • 标记为非可信事件:isTrusted: false 表示此事件由脚本生成,而非用户直接操作触发。
  1. addDoubleTapListener(obj, handler)函数:添加双击监听:
  • ​核心逻辑:
    1. ​双重监听:

      • 直接监听原生 dblclick(桌面浏览器有效)。
      • 通过 click 事件模拟移动端双击(simDblclick)。
    2. 过滤非触控事件:

      • pointerType === 'mouse':排除鼠标操作。
      • sourceCapabilities.firesTouchEvents:仅处理触控或笔触(Chrome 特性)。 ​
    3. 避免 <label> 误触发:

      • 若事件路径中存在关联 <label for> 但无对应表单元素(如 <input>),则忽略点击。
    4. 时间间隔判断:

      • 两次 click 间隔小于 200ms 视为双击,触发自定义 dblclick 事件。
  1. removeDoubleTapListener(obj, handlers)函数:移除双击监听
  • ​目的:移除之前通过addDoubleTapListener添加的 dblclick 和 simDblclick 事件监听器。

  • 关键点:需传入之前返回的handles对象,确保移除正确的监听函数。

# 关键设计思想

  1. 移动端兼容性: 移动端浏览器通常不直接支持dbclick事件,通过快速连续点击(click)模拟双击行为

  2. 避免冲突:

    • 过滤 <label> 元素点击,防止其关联的表单元素(如复选框)被误操作。
    • 区分触控和鼠标事件,避免重复处理。 ​
  3. 性能优化:

    • 使用 200ms 间隔判断双击,平衡响应速度和误触概率。
    • 通过 DomEvent.getPropagationPath(e) 获取事件传播路径,精确控制事件逻辑。

# 使用场景

  • ​地图双击缩放:用户快速双击地图时,触发放大地图的操作。
  • 移动端手势支持:在触控设备上实现与桌面浏览器一致的双击交互。 ​

# 潜在问题与注意事项

​

  1. 事件可信度: 模拟的 dblclick 事件 isTrusted: false,某些安全策略可能限制其行为(如阻止默认动作)。

  2. ​时间间隔敏感性:

200ms 的间隔可能导致部分用户操作未被识别为双击,需根据实际需求调整。

  1. 浏览器兼容性:
  • sourceCapabilities 是 Chrome 特有属性,其他浏览器可能需额外兼容处理。
  • DomEvent.getPropagationPath 是 Leaflet 内部方法,用于获取事件传播路径(等价于 e.composedPath())。 ​

# 总结

​

  • 核心功能:通过监听快速连续的 click 事件模拟 dblclick,解决移动端兼容性问题。 ​
  • 设计亮点:
    • 双重事件监听(原生 + 模拟)兼顾不同环境。
    • 路径过滤避免
    • 严格区分触控与鼠标事件。 ​
  • 适用场景:需要跨平台支持双击交互的 Web 应用(尤其是地图库)。
编辑 (opens new window)
上次更新: 2025/03/21, 01:49:37
DomEvent.Pointer
Draggable拖拽实现

← DomEvent.Pointer Draggable拖拽实现→

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