Observable类
# 概述
本文主要会讲述Observable
类以及扩展介绍下event.js
中的方法,二者也都和 Openlayers 中的事件机制有关。
# 源码剖析
# Observable
类
Observable
类继承了EventTarget
类,是一个抽象类,主要是对外提供注册事件和取消监听的钩子,其实现如下:
class Observable extends EventTarget {
constructor() {
super();
this.on = this.onInternal;
this.once = this.onceInternal;
this.un = this.unInternal;
this.revision_ = 0;
}
changed() {
++this.revision_;
this.dispatchEvent(EventType.CHANGE);
}
getRevision() {
return this.revision_;
}
onInternal(type, listener) {
if (Array.isArray(type)) {
const len = type.length;
const keys = new Array(len);
for (let i = 0; i < len; ++i) {
keys[i] = listen(this, type[i], listener);
}
return keys;
}
return listen(this, type, listener);
}
onceInternal(type, listener) {
let key;
if (Array.isArray(type)) {
const len = type.length;
key = new Array(len);
for (let i = 0; i < len; ++i) {
key[i] = listenOnce(this, type[i], listener);
}
} else {
key = listenOnce(this, type, listener);
}
listener.ol_key = key;
return key;
}
unInternal(type, listener) {
const key = listener.ol_key;
if (key) {
unByKey(key);
} else if (Array.isArray(type)) {
for (let i = 0, ii = type.length; i < ii; ++i) {
this.removeEventListener(type[i], listener);
}
} else {
this.removeEventListener(type, listener);
}
}
}
function unByKey(key) {
if (Array.isArray(key)) {
for (let i = 0, ii = key.length; i < ii; ++i) {
unlistenByKey(key[i]);
}
} else {
unlistenByKey(key);
}
}
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
Observable
类中定义的变量和方法如下:
revision
变量
revision_
变量用于记录修订次数,初始值为0
;调用changed
方法时,revision_
会自增1
,然后调用this.dispatchEvent
方法派生事件;可以通过getRevision
方法获取revision_
的值。
on
方法
on
方法就是用于注册监听事件。比如map
为Map
类的实例对象,map.on('pointermove',(evt)=>{})
本质上就是调用这个on
方法,un
和once
同理。
on
方法接受两个参数,类型type
和注册事件listener
。type
可以是一个字符串也可以是一个数组,如果为数组,则for
循环遍历调用listen
方法,并将其返回值按顺序包装成一个数组返回;如果时一个字符串,则直接调用listen
方法,返回listen
方法的结果。
once
方法
once
方法和on
方法类似,不过其内部调用的是listenOnce
方法,意思就是只监听一次,另外once
方法会用注册事件的ol_key
属性记录listenOnce
方法执行的结果。
un
方法
un
方法会先判断注册事件的ol_key
值,该属性可以区分事件注册时调用的是on
还是once
方法;若key
存在,即注册调用了once
方法,则会调用unByKey
解除监听;否则调用this.removeListener
解除。
unByKey
方法
unByKey
不属于Observable
类的方法,只是一个工具函数,接受一个key
参数;若key
是数组,则循环调用unlistenByKey
;否则直接调用unlistenByKey
解除监听。
# event.js
在上面提到的listen
、listenOnce
和unlistenByKey
方法都是在event.js
中定义的,借此正好介绍下这三个方法
listen
方法
首先看一下实现,如下:
export function listen(target, type, listener, thisArg, once) {
if (once) {
const originalListener = listener;
listener = function () {
target.removeEventListener(type, listener);
originalListener.apply(thisArg ?? this, arguments);
};
} else if (thisArg && thisArg !== target) {
listener = listener.bind(thisArg);
}
const eventsKey = {
target: target,
type: type,
listener: listener,
};
target.addEventListener(type, listener);
return eventsKey;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在Observable
类中调用listen
方法时,参数传值是listen(this,type,listener)
,此时this.Arg
、once
都是是undefined
,实际上还是调用的this.addEventListener
方法,因此在Observable
类中取消on
方法注册的事件是调用this.removeEventListener
就形成闭环了。简单理解,listen
方法返回值的key
值就是一个包含参数的对象。
listenOnce
方法
listenOnce
方法内部还是调用的listen
方法,就是调用listen
方法时参数once
值为true
,此时在listen
方法中就会对参数listener
进行一层封装,在执行dispatchEvent
方法派生该事件时,就会先取消监听,再执行注册事件。
export function listenOnce(target, type, listener, thisArg) {
return listen(target, type, listener, thisArg, true);
}
2
3
unlistenByKey
方法
unlistenByKey
方法实现如下:
export function unlistenByKey(key) {
if (key && key.target) {
key.target.removeEventListener(key.type, key.listener);
clear(key);
}
}
2
3
4
5
6
这个方法之所以存在就是因为listenOnce
方法注册组件时,调用addEventListener
注册组件注册的是包装后的listener
,而该listener
是挂载在key.target
上。
# 总结
本文主要讲述了Observable
类和event.js
中一些方法,Observable
类实质上就借助event.js
中工具函数对其父类EventTarget
中的addEventListener
和removeListener
方法的一个应用,方便用户操作调用。