-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
126 lines (122 loc) · 4.28 KB
/
index.js
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
function isFunction(obj) {
return typeof obj === 'function';
}
function isString(obj) {
return typeof obj === 'string';
}
/** 事件委托 */
class Delegate {
constructor(vnode) {
this.vnode = vnode;
this._map = {};
// 用来给委托任务编号,事件触发时按顺序执行
this._index = 0;
}
/**
* 将事件处理函数添加到当前节点
* @param {string} events 事件名,多个事件用空格分隔
* @param {string} selector 选择器
* @param {function} handler 事件处理函数
*/
on(events, selector, handler) {
let { _map, vnode } = this;
if (isFunction(selector)) {
handler = selector;
selector = null;
}
if (isString(events) && isFunction(handler)) {
let index = this._index++;
if (!isString(selector)) {
selector = null;
}
events.split(/\s+/).forEach(eventType => {
if (eventType) {
if (!_map[eventType]) {
_map[eventType] = [];
// 事件名采用驼峰形式
let eventBindName = 'on' + eventType.replace(/^\w/, w => w.toUpperCase());
let oldHandler = vnode.attributes[eventBindName];
if (!isFunction(oldHandler)) {
oldHandler = null;
}
vnode.attributes[eventBindName] = event => {
if (oldHandler) {
oldHandler(event);
}
this.exec(eventType, event);
};
}
_map[eventType].push({ index, selector, handler });
}
});
}
return this;
}
/**
* 执行附加到节点上的指定事件的所有处理函数
* @param {string} eventType
* @param {Event} event
*/
exec(eventType, event) {
let root = event.currentTarget;
let target = event.target;
let execList = [];
let list = this._map[eventType];
// 查找子元素命中的委托
while (target && root && target != root) {
let matches = {};
for (let i = 0; i < list.length; i++) {
let { index, selector, handler } = list[i];
if (selector) {
if (matches[selector] == null) {
let finds = root.querySelectorAll(selector);
matches[selector] = Array.prototype.indexOf.call(finds, target) > -1;
}
if (matches[selector]) {
execList.push({
index,
target,
handler,
event: Object.assign({}, event, { target })
});
}
}
}
target = target.parentElement || root;
}
// 查找当前元素命中的委托
list.forEach(({ index, selector, handler }) => {
if (!selector) {
execList.push({ index, target: root, handler, event });
}
});
// 依次执行命中的委托
execList.sort((a, b) => a.index - b.index);
while (execList.length) {
let { target, handler, event } = execList.shift();
// 在事件处理函数中返回 false 时,停止后续的委托处理
if (handler.call(target, event) === false) {
event.cancelBubble = true;
event.defaultPrevented = true;
return false;
}
}
}
}
//#region 通过vnode钩子函数解析on属性,并进行事件委托
const { options } = preact;
let oldHook = options.vnode; // 保存之前的钩子函数
options.vnode = vnode => {
// 设置了on属性时,创建Delegate对象进行委托
let { on } = vnode.attributes || {};
if (on && isFunction(on)) {
on(new Delegate(vnode));
delete vnode.attributes.on;
}
// 执行之前的钩子函数
if (oldHook) {
oldHook(vnode);
}
};
//#endregion
export default Delegate;