源码分析之Openlayers的核心EventTarget类的实现

概述

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

源码剖析

Disposable

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

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

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

  disposeInternal() {}
}

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];
        }
      }
    }
  }
}
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,若propagatefalse,则propagate赋值为false;若propagatetrue,则当evt.propagationStoppedtrue时,propagate才为false,退出循环。

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

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

  • disposeInternal

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

export function clear(object) {
  for (const property in object) {
    delete object[property];
  }
}
  • getListeners

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

  • hasListeners

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

  • removeListener

removeListener方法用于移除注册的监听事件。该方法接收两个参数typelistener.
其原理是当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;
  }
}

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

总结

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jinuss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值