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-19
目录

DomUtil

# 概述

DomUtil模块是Leaflet中用于处理 DOM 操作和事件的核心工具函数集合,这些工具函数主要用于处理 DOM 元素的样式、位置、变换、事件等操作。

# 源码分析

# 源码实现如下

DomUtil源码实现如下:

export var TRANSFORM = testProp([
  "transform",
  "webkitTransform",
  "OTransform",
  "MozTransform",
  "msTransform",
]);

export var TRANSITION = testProp([
  "webkitTransition",
  "transition",
  "OTransition",
  "MozTransition",
  "msTransition",
]);

export var TRANSITION_END =
  TRANSITION === "webkitTransition" || TRANSITION === "OTransition"
    ? TRANSITION + "End"
    : "transitionend";

export function get(id) {
  return typeof id === "string" ? document.getElementById(id) : id;
}

export function getStyle(el, style) {
  var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);

  if ((!value || value === "auto") && document.defaultView) {
    var css = document.defaultView.getComputedStyle(el, null);
    value = css ? css[style] : null;
  }
  return value === "auto" ? null : value;
}

export function create(tagName, className, container) {
  var el = document.createElement(tagName);
  el.className = className || "";

  if (container) {
    container.appendChild(el);
  }
  return el;
}

export function remove(el) {
  var parent = el.parentNode;
  if (parent) {
    parent.removeChild(el);
  }
}

export function empty(el) {
  while (el.firstChild) {
    el.removeChild(el.firstChild);
  }
}

export function toFront(el) {
  var parent = el.parentNode;
  if (parent && parent.lastChild !== el) {
    parent.appendChild(el);
  }
}

export function toBack(el) {
  var parent = el.parentNode;
  if (parent && parent.firstChild !== el) {
    parent.insertBefore(el, parent.firstChild);
  }
}

export function hasClass(el, name) {
  if (el.classList !== undefined) {
    return el.classList.contains(name);
  }
  var className = getClass(el);
  return (
    className.length > 0 &&
    new RegExp("(^|\\s)" + name + "(\\s|$)").test(className)
  );
}

export function addClass(el, name) {
  if (el.classList !== undefined) {
    var classes = Util.splitWords(name);
    for (var i = 0, len = classes.length; i < len; i++) {
      el.classList.add(classes[i]);
    }
  } else if (!hasClass(el, name)) {
    var className = getClass(el);
    setClass(el, (className ? className + " " : "") + name);
  }
}

export function removeClass(el, name) {
  if (el.classList !== undefined) {
    el.classList.remove(name);
  } else {
    setClass(
      el,
      Util.trim((" " + getClass(el) + " ").replace(" " + name + " ", " "))
    );
  }
}

export function setClass(el, name) {
  if (el.className.baseVal === undefined) {
    el.className = name;
  } else {
    // in case of SVG element
    el.className.baseVal = name;
  }
}

export function getClass(el) {
  if (el.correspondingElement) {
    el = el.correspondingElement;
  }
  return el.className.baseVal === undefined
    ? el.className
    : el.className.baseVal;
}

export function setOpacity(el, value) {
  if ("opacity" in el.style) {
    el.style.opacity = value;
  } else if ("filter" in el.style) {
    _setOpacityIE(el, value);
  }
}

function _setOpacityIE(el, value) {
  var filter = false,
    filterName = "DXImageTransform.Microsoft.Alpha";

  // filters collection throws an error if we try to retrieve a filter that doesn't exist
  try {
    filter = el.filters.item(filterName);
  } catch (e) {
    if (value === 1) {
      return;
    }
  }

  value = Math.round(value * 100);

  if (filter) {
    filter.Enabled = value !== 100;
    filter.Opacity = value;
  } else {
    el.style.filter += " progid:" + filterName + "(opacity=" + value + ")";
  }
}

export function testProp(props) {
  var style = document.documentElement.style;

  for (var i = 0; i < props.length; i++) {
    if (props[i] in style) {
      return props[i];
    }
  }
  return false;
}

export function setTransform(el, offset, scale) {
  var pos = offset || new Point(0, 0);

  el.style[TRANSFORM] =
    (Browser.ie3d
      ? "translate(" + pos.x + "px," + pos.y + "px)"
      : "translate3d(" + pos.x + "px," + pos.y + "px,0)") +
    (scale ? " scale(" + scale + ")" : "");
}

export function setPosition(el, point) {
  el._leaflet_pos = point;
  if (Browser.any3d) {
    setTransform(el, point);
  } else {
    el.style.left = point.x + "px";
    el.style.top = point.y + "px";
  }
}

export function getPosition(el) {
  return el._leaflet_pos || new Point(0, 0);
}

export var disableTextSelection;
export var enableTextSelection;
var _userSelect;
if ("onselectstart" in document) {
  disableTextSelection = function () {
    DomEvent.on(window, "selectstart", DomEvent.preventDefault);
  };
  enableTextSelection = function () {
    DomEvent.off(window, "selectstart", DomEvent.preventDefault);
  };
} else {
  var userSelectProperty = testProp([
    "userSelect",
    "WebkitUserSelect",
    "OUserSelect",
    "MozUserSelect",
    "msUserSelect",
  ]);

  disableTextSelection = function () {
    if (userSelectProperty) {
      var style = document.documentElement.style;
      _userSelect = style[userSelectProperty];
      style[userSelectProperty] = "none";
    }
  };
  enableTextSelection = function () {
    if (userSelectProperty) {
      document.documentElement.style[userSelectProperty] = _userSelect;
      _userSelect = undefined;
    }
  };
}

export function disableImageDrag() {
  DomEvent.on(window, "dragstart", DomEvent.preventDefault);
}

export function enableImageDrag() {
  DomEvent.off(window, "dragstart", DomEvent.preventDefault);
}

var _outlineElement, _outlineStyle;

export function preventOutline(element) {
  while (element.tabIndex === -1) {
    element = element.parentNode;
  }
  if (!element.style) {
    return;
  }
  restoreOutline();
  _outlineElement = element;
  _outlineStyle = element.style.outlineStyle;
  element.style.outlineStyle = "none";
  DomEvent.on(window, "keydown", restoreOutline);
}

export function restoreOutline() {
  if (!_outlineElement) {
    return;
  }
  _outlineElement.style.outlineStyle = _outlineStyle;
  _outlineElement = undefined;
  _outlineStyle = undefined;
  DomEvent.off(window, "keydown", restoreOutline);
}

export function getSizedParentNode(element) {
  do {
    element = element.parentNode;
  } while (
    (!element.offsetWidth || !element.offsetHeight) &&
    element !== document.body
  );
  return element;
}

export function getScale(element) {
  var rect = element.getBoundingClientRect(); // Read-only in old browsers.

  return {
    x: rect.width / element.offsetWidth || 1,
    y: rect.height / element.offsetHeight || 1,
    boundingClientRect: rect,
  };
}
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

# 主要工具函数介绍

  1. TRANSFORM和TRANSITION
  • 作用:检测浏览器支持的 CSS 变换(transform)和过渡(transition)属性
  • 实现:通过testProp函数遍历一组可能的属性名称,返回浏览器支持的第一个属性
  • 意义:跨浏览器兼容性处理,确保在不同浏览器中正确应用 CSS 变换和过渡
  1. TRANSITION_END
  • ​ 作用:确定浏览器支持的 transitionend 事件名称。
  • 实现:根据 TRANSITION 属性的值,返回对应的事件名称(如 webkitTransitionEnd 或 transitionend)。
  • ​ 意义:确保在 CSS 过渡结束时正确触发事件
  1. DOM 操作工具函数
  • get(id)

    • 作用:通过 ID 获取 DOM 元素。
    • 实现:如果传入的是字符串,调用 document.getElementById;否则直接返回传入的值。
  • getStyle(el, style)

    • ​ 作用:获取元素的样式值。
    • 实现:优先从 el.style 或 el.currentStyle 中获取样式值,如果未找到或值为 auto,则通过 getComputedStyle 获取。
  • create(tagName, className, container)

    • 作用:创建并返回一个 DOM 元素。
    • 实现:使用 document.createElement 创建元素,并可选地将其附加到指定容器中。
  • remove(el)

    • 作用:从 DOM 中移除元素。
    • 实现:调用 parentNode.removeChild。
  • empty(el)

    • 作用:清空元素的所有子节点。
    • 实现:循环移除 el.firstChild。
  • toFront(el) 和 toBack(el)

    • ​ 作用:将元素移动到其父容器的顶部或底部。
    • 实现:通过 appendChild 或 insertBefore 调整元素的位置。

​4. 类名操作工具函数

  • hasClass(el, name)

    • 作用:检查元素是否包含指定的类名。
    • 实现:优先使用 el.classList.contains,否则通过正则表达式匹配。
  • addClass(el, name) 和 removeClass(el, name)

    • 作用:添加或移除元素的类名。
    • 实现:优先使用 el.classList,否则通过字符串操作修改 className。
  • setClass(el, name) 和 getClass(el)

    • 作用:设置或获取元素的类名。
    • 实现:处理普通元素和 SVG 元素的兼容性。

​5. 透明度操作工具函数

  • setOpacity(el, value)

    • 作用:设置元素的透明度。
    • 实现:优先使用 opacity 属性,否则通过 IE 的 filter 属性实现。
  • setOpacityIE(el, value)

    • 作用:在 IE 中设置透明度。
    • 实现:通过 DXImageTransform.Microsoft.Alpha 滤镜实现。 ​
  1. 变换和位置操作工具函数
  • testProp(props)

    • 作用:检测浏览器支持的 CSS 属性。
    • 实现:遍历传入的属性列表,返回第一个支持的属性。
  • setTransform(el, offset, scale)

    • 作用:设置元素的变换(平移和缩放)。
    • 实现:根据浏览器支持,使用 translate 或 translate3d。
  • setPosition(el, point) 和 getPosition(el)

    • 作用:设置或获取元素的位置。
    • 实现:优先使用 transform,否则通过 left 和 top 实现。

​ 7. 文本选择和图像拖拽工具函数

  • disableTextSelection() 和 enableTextSelection()

    • 作用:禁用或启用文本选择。
    • 实现:通过 selectstart 事件或 userSelect 属性实现。
  • disableImageDrag() 和 enableImageDrag()

    • 作用:禁用或启用图像拖拽。
    • 实现:通过 dragstart 事件实现。 ​
  1. 轮廓线操作工具函数
  • preventOutline(element) 和 restoreOutline()
    • 作用:禁用或恢复元素的轮廓线。
    • 实现:通过修改 outlineStyle 实现。
  1. 其他工具函数
  • getSizedParentNode(element)

    • 作用:获取具有实际尺寸的父节点。
    • 实现:循环查找父节点,直到找到具有 offsetWidth 和 offsetHeight 的节点。
  • getScale(element)

    • 作用:获取元素的缩放比例。
    • 实现:通过 getBoundingClientRect 和 offsetWidth/Height 计算。

# 总结

这段代码是 Leaflet 中用于处理 DOM 操作和事件的工具函数集合,涵盖了元素创建、删除、样式操作、变换、事件处理等功能。它的设计目标是:

  1. 跨浏览器兼容性:通过检测和适配不同浏览器的属性和事件名称。
  2. 轻量高效:使用原生 DOM API,避免不必要的依赖。
  3. 模块化:每个函数功能独立,易于复用和扩展。

这些工具函数为 Leaflet 的核心功能(如地图渲染、交互、动画等)提供了基础支持。

编辑 (opens new window)
上次更新: 2025/03/20, 00:55:00
DomEvent
DomEvent.Pointer

← DomEvent DomEvent.Pointer→

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