事件绑定与传递
事件绑定与传递
事件监听与响应
上面提及的绑定方式主要是如下三种
element.addEventListener('type', obj.method.bind(obj))
element.addEventListener('type', function (event) {})
element.addEventListener('type', (event) => {})
不过这种方式会创建大量新的匿名事件监听器,并且即使已经不需要再使用的时候也无法移除。这可能会导致大量的性能损耗以及不可预知的逻辑错误,在未知的用户交互或者冒泡的时候出现问题,相对而言安全一点的绑定方式是:
const handler = function() {
console.log("Tada!");
};
element.addEventListener("click", handler);
// Later on
element.removeEventListener("click", handler);
命名函数,可以保证之后能够移除
element.addEventListener("click", function click(e) {
if (someCondition) {
return e.currentTarget.removeEventListener("click", click);
}
});
一个更好地方式
function handleEvent(
eventName,
{ onElement, withCallback, useCapture = false } = {},
thisArg
) {
const element = onElement || document.documentElement;
function handler(event) {
if (typeof withCallback === "function") {
withCallback.call(thisArg, event);
}
}
handler.destroy = function() {
return element.removeEventListener(eventName, handler, useCapture);
};
element.addEventListener(eventName, handler, useCapture);
return handler;
}
// Anytime you need
const handleClick = handleEvent("click", {
onElement: element,
withCallback: event => {
console.log("Tada!");
}
});
// And anytime you want to remove it
handleClick.destroy();
export const addEventListener = (node, event, listener) =>
node.addEventListener
? node.addEventListener(event, listener, false)
: node.attachEvent("on" + event, listener);
export const removeEventListener = (node, event, listener) =>
node.removeEventListener
? node.removeEventListener(event, listener, false)
: node.detachEvent("on" + event, listener);
参数传递
无论何种绑定方式,都会存在着一个参数传递问题。
- 使用闭包方式进行参数传递
function callback(a, b) {
return function() {
console.log("sum = ", a + b);
};
}
var x = 1,
y = 2;
document.getElementById("someelem").addEventListener("click", callback(x, y));
- 使用
bind 函数进行参数传递
const alertText = function(text) {
alert(text);
};
document
.getElementById("someelem")
.addEventListener("click", alertText.bind(this, "hello"));
- Auto Injected Event
有时候需要在一个函数中判断点击的源,这个时候可以使用默认的
function switchResources(event) {
switch (event.target.id) {
case "button1":
content = "Button 1 clicked.";
displayLog();
break;
case "button2":
content = "Button 2 clicked.";
displayLog();
break;
case "button3":
content = "Button 3 clicked.";
displayLog();
break;
}
}
button1.addEventListener("click", switchResources, false);
button2.addEventListener("click", switchResources, false);
button3.addEventListener("click", switchResources, false);
Event 对象
事件流,冒泡与捕获
事件流描述的是从页面接收事件的顺序,

“
document->html->body->div->body->html->document
在
Event Delegation | 事件委托
<ul onclick="alert(event.type + '!')">
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
如果你点击了任何的
var newLi = document.createElement("li");
newLi.innerHTML = "Four";
myUL.appendChild(newLi);
var newLi = document.createElement("li");
newLi.innerHTML = "Four";
myUL.appendChild(newLi);
如果没有用事件委托的话,那么你需要重新绑定 onclick
函数到每一个新增的li
节点上,而如果用事件委托的话你完全不需要关心unbind
操作来避免内存泄露。
YAHOO.example.toggleEventListen = {
hide: function() {
// add a CSS class to the main UL to hide all nested list items
YAHOO.util.Dom.addClass(this, "dynamic"); // get all ULs in this one and loop over them
var uls = this.getElementsByTagName("ul");
for (var i = 0; i < uls.length; i++) {
// get the link above this UL and add an event listener pointing to the toggle method
var parentLink = uls[i].parentNode.getElementsByTagName("a")[0];
YAHOO.util.Event.addListener(
parentLink,
"click",
YAHOO.example.toggleEventListen.toggle
);
}
},
toggle: function(e) {
// get the first nested UL and toggle its display property
var ul = this.parentNode.getElementsByTagName("ul")[0];
if (ul.style.display == "none" || ul.style.display == "") {
ul.style.display = "block";
} else {
ul.style.display = "none";
} // stop the link from being followed
YAHOO.util.Event.preventDefault(e);
}
};
// 基于事件委托的事件处理
YAHOO.example.toggleEventDelegation = {
hide: function() {
// add a CSS class to the main UL to hide all nested list items
YAHOO.util.Dom.addClass(this, "dynamic"); // Add one event listener to the element pointing to the toggle method
YAHOO.util.Event.addListener(
this,
"click",
YAHOO.example.toggleEventDelegation.toggle
);
},
toggle: function(e) {
// Check where the event came from
var origin = YAHOO.util.Event.getTarget(e); // Compare with the right node name and test if the parent LI contains a list
if (
origin.nodeName.toLowerCase() === "a" &&
origin.parentNode.getElementsByTagName("ul").length > 0
) {
// get the first nested UL and toggle its display property
var ul = origin.parentNode.getElementsByTagName("ul")[0];
if (ul.style.display == "none" || ul.style.display == "") {
ul.style.display = "block";
} else {
ul.style.display = "none";
} // stop the link from being followed
YAHOO.util.Event.preventDefault(e);
}
}
};