想要实现类似于 jQuery 中类似于 .on()
中的 Delegated Event,却又不想用 jQuery 怎么破?
先看问题
举个例子说明一下,有一组按钮,每当点击其中一个按钮,就把这个按钮的状态变为 "active",再点一下就取消 "active" 状态,代码如下:
<ul class="toolbar">
<li><button class="btn">Pencil</button></li>
<li><button class="btn">Pen</button></li>
<li><button class="btn">Eraser</button></li>
</ul>
用最普通的 js 可以这样处理:
var buttons = document.querySelectorAll(".toolbar .btn");
for(var i = 0; i < buttons.length; i++) {
var button = buttons[i];
button.addEventListener("click", function() {
if(!button.classList.contains("active"))
button.classList.add("active");
else
button.classList.remove("active");
});
}
不过并没有达到预期的效果。
闭包惹的祸
有经验的读者可能已经看出不对劲的地方了。那是因为处理点击事件的 handler 函数形成独立的作用域,是其中的 button
会尝试去更上级的作用域去寻找。
不过真正当你去点击按钮的时候,循环已经完成,button
就会一直指向最后一个按钮,所以效果就是不管点击哪个按钮都是最后一个按钮的状态在变化。
把代码改善一下:
var buttons = document.querySelectorAll(".toolbar button");
var createToolbarButtonHandler = function(button) {
return function() {
if(!button.classList.contains("active"))
button.classList.add("active");
else
button.classList.remove("active");
};
};
for(var i = 0; i < buttons.length; i++) {
button.addEventListener("click", createToolBarButtonHandler(buttons[i]));
}