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)
  • 核心基类

    • EventTarget类
      • 概述
      • 源码剖析
        • Disposable类
        • Target类
        • EventTarget变量
        • EventTarget方法
        • Event类
      • 总结
    • Observable类
    • BaseObject类
  • Control控件篇

  • Geom几何图形篇

  • Layer图层篇

  • Renderer篇

  • Feature篇

  • style样式篇

  • 《Openlayers源码》笔记
  • 核心基类
东流
2024-12-02
目录

EventTarget类

# 概述

EventTarget类是 Openlayers 中许多类实现的基类,主要和事件监听触发有关。

# 源码剖析

# Disposable类

EventTarget类继承于Disposable类,其实现如下:

class Disposable {
  constructor() {
    this.disposed = false;
  }

  dispose() {
    if (!this.disposed) {
      this.disposed = true;
      this.disposeInternal();
    }
  }

  disposeInternal() {}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Disposable类中定义了一个disposed变量,默认值为false,两个方法dispose()和disposeInternal()。

dispose译为处置,由此推定Disposable类就是用于在函数调用后执行某些clean up操作。

# Target类

EventTarget类即target实现如下:

class Target extends Disposable {
  constructor(target) {
    super();
    this.eventTarget_ = target;
    this.pendingRemovals_ = null;
    this.dispatching_ = null;
    this.listeners_ = null;
  }

  addEventListener(type, listener) {
     if (!type || !listener) {
      return;
    }
    const listeners = this.listeners_ || (this.listeners_ = {});
    const listenersForType = listeners[type] || (listeners[type] = []);
    if (!listenersForType.includes(listener)) {
      listenersForType.push(listener);
    }
  }
  dispatchEvent(event) {
     const isString = typeof event === 'string';
    const type = isString ? event : event.type;
    const listeners = this.listeners_ && this.listeners_[type];
    if (!listeners) {
      return;
    }

    const evt = isString ? new Event(event) : /** @type {Event} */ (event);
    if (!evt.target) {
      evt.target = this.eventTarget_ || this;
    }
    const dispatching = this.dispatching_ || (this.dispatching_ = {});
    const pendingRemovals =
      this.pendingRemovals_ || (this.pendingRemovals_ = {});
    if (!(type in dispatching)) {
      dispatching[type] = 0;
      pendingRemovals[type] = 0;
    }
    ++dispatching[type];
    let propagate;
    for (let i = 0, ii = listeners.length; i < ii; ++i) {
      if ('handleEvent' in listeners[i]) {
        propagate = /** @type {import("../events.js").ListenerObject} */ (
          listeners[i]
        ).handleEvent(evt);
      } else {
        propagate = /** @type {import("../events.js").ListenerFunction} */ (
          listeners[i]
        ).call(this, evt);
      }
      if (propagate === false || evt.propagationStopped) {
        propagate = false;
        break;
      }
    }
    if (--dispatching[type] === 0) {
      let pr = pendingRemovals[type];
      delete pendingRemovals[type];
      while (pr--) {
        this.removeEventListener(type, VOID);
      }
      delete dispatching[type];
    }
    return propagate;
  }
  disposeInternal() {
     this.listeners_ && clear(this.listeners_);
  }
  getListeners(type) {
    return (this.listeners_ && this.listeners_[type]) || undefined;
  }
  hasListener(type) {
    if (!this.listeners_) {
      return false;
    }
    return type
      ? type in this.listeners_
      : Object.keys(this.listeners_).length > 0;
  }
  removeEventListener(type, listener) {
    if (!this.listeners_) {
      return;
    }
    const listeners = this.listeners_[type];
    if (!listeners) {
      return;
    }
    const index = listeners.indexOf(listener);
    if (index !== -1) {
      if (this.pendingRemovals_ && type in this.pendingRemovals_) {
        // make listener a no-op, and remove later in #dispatchEvent()
        listeners[index] = VOID;
        ++this.pendingRemovals_[type];
      } else {
        listeners.splice(index, 1);
        if (listeners.length === 0) {
          delete this.listeners_[type];
        }
      }
    }
  }
}
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

# EventTarget变量

EventTarget类接受一个名为target的参数,有四个私有变量,如下:

  • eventTarget_:保存参数target
  • pendingRemovals:对象,记录待移除的监听事件数量
  • dispatching_:对象,记录待派发的事件数量
  • listeners_:对象,键值分别对应事件类型和监听事件(回调函数)

# EventTarget方法

  • addEventListener

addEventListener方法就是注册事件监听到变量this.listeners_中,且同一类型的同一个监听事件只添加一次,键值对分别对应事件类型和事件数组。

  • dispatchEvent

dispatchEvent方法主要就是用来派发事件或者是触发回调,接受一个event参数。 其原理是:

  • 第一步:先检查参数event的类型,若它是一个字符串,则表示它是一个type,否则将它的type属性作为type,以此来判断this.listeners_中是否注册过该type的监听,若不存在,则return;否则进行第二步骤

  • 第二步:若参数event是一个字符串,则调用Event类,实例化一个evt;否则,evt的值就是event;然后确定evt.target,若this.eventTarget_存在,则evt.target取值就是它,否则就是this

  • 第三步:初始化this.dispatching_[type]和this.pengdingRemovals_[type]的值为0,然后this.dispatching_[type]自增1

  • 第四步:定义一个变量propagate,用来标记事件是否继续传播;然后遍历this.listener_[type],若handleEvent方法包含在注册事件中,则执行注册事件的handleEvent方法,参数为evt,返回值赋值给propagate变量;若注册事件中不包含handleEvent方法,则调用call方法执行该注册事件,参数为evt,返回值赋值给propagate变量;最后判断propagate的值和evt.propagationStopped,若propagate为false,则propagate赋值为false;若propagate为true,则当evt.propagationStopped为true时,propagate才为false,退出循环。

  • 第五步:注册事件执行完后,调用this.removeEventListener清除

  • 第六步:最后返回变量propagation

  • disposeInternal

disposeInternal方法就是将this.listeners置空,clear方法用于清除删除对象上的所有可枚举的属性,其实现如下

export function clear(object) {
  for (const property in object) {
    delete object[property];
  }
}
1
2
3
4
5
  • getListeners

getListeners方法就是根据type获取对应的事件数组,若不存在则返回undefined

  • hasListeners

hasListeners方法用于判断this.listeners_中是否存在type,若存在则返回true,否则判断this.listeners_中是否存在其它类型的监听

  • removeListener

removeListener方法用于移除注册的监听事件。该方法接受两个参数type和listener. 其原理是当this.listener_[type]存在时,就判断this.listener_[type]是否包含listener,如果包含,则判断this.pengdingRemovals_[type]的值是否为0,若为0,则调用splice移除this.listener_[type]中对应位置的listener,若this.listener_[type]的长度为0,则删除this.listeners_中对应的键值对;若this.pengdingRemovals_[type]不为0,则将该注册事件置为空函数,索引值自增

# Event类

在上面介绍dispatchEvent时,提到通过new Event(event)实例化一个evt,其中Event类如下:

class BaseEvent{
  constructor(type){
    this.propagationStopped;
    this.defaultPrevented;
    this.type = type;
    this.target = null;
  }

  preventDefault() {
    this.defaultPrevented = true;
  }

  stopPropagation() {
    this.propagationStopped = true;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Event类就是定义了一个事件最基本的属性和方法

# 总结

本文介绍了EventTarget类的几种方法和属性以及dispatchEvent的核心原理,该方法在Openlayers中占据举重若轻的地位。

编辑 (opens new window)
上次更新: 2024/12/11, 10:30:03
Observable类

Observable类→

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