关于 JavaScript 的事件绑定在网上已经有不少相关的资料了
今天这篇文章也是在被同事问及的时候才顺便把它记录下来
算是 JavaScript 事件绑定中的一个小技巧
如果能在工作中善加利用
会有出其不意的效果
其实没有什么新的知识点只是为了方便其他有需要的朋友们翻阅对自己而言也算是一个积累所以只能算是闲谈 JavaScript老鸟们可以尽情飘过
在进入正题之前先提个问题热热身吧
现在有如下 HTML 结构
复制代码 代码如下:
<div id="wrap">
<input type="button" value="按钮一" />
<input type="button" value="按钮二" />
<input type="button" value="按钮三" />
<input type="button" value="按钮四" />
<input type="button" value="按钮五" />
</div>
以及如下 JavaScript 代码
复制代码 代码如下:
var wrap = document
getElementById(
wrap
)
inputs = wrap
getElementsByTagName(
input
);
for (var i =
l = inputs
length; i < l; i++) {
inputs[i]
onclick = function () {
alert(i);
}
}
请问这样执行的结果是什么?
/***************************分割线***************************/
如果你的回答是“点击按钮时 alert 当前按钮的索引值 i”那你就中了我的圈套了大家不妨试试无论你点击哪个按钮它都会alert()
这个看似理所当然的结果为什么会和实际情况不同呢?其实也是很好理解的
因为 onclick 只是事件绑定而不是执行当我们执行 onclick 事件的时候这时的 i 已经是循环以后的值了照这样看每个按钮都alert() 也就不足为奇了
那么如果我们要怎么实现“点击按钮时alert 当前按钮的索引值 i”呢?这里就要用到 JavaScript 中暗藏玄机的一个概念“闭包”我们可以用闭包的方式改写以上 JS把 for 循环中的 i 值保存在内存中代码如下
复制代码 代码如下:
var wrap = document
getElementById(
wrap
)
inputs = wrap
getElementsByTagName(
input
);
for (var i =
l = inputs
length; i < l; i++) {
(function (cur) {
inputs[cur]
onclick = function () {
alert(cur);
}
})(i)
}
再试试效果?确实能 alert 出相应的索引值了不过至此为止还只是开胃菜正题才刚刚开始!
以 上的方法我们是通过循环 + 闭包给 button 按钮上绑定事件我们知道在 JavaScript 中函数也是对象对象就会占用内存现在的例子中只有 个按钮或许你会认为这样的性能开销可以忽略不计但是如果当我们有 个甚至 个按钮的时候IE 已经哭了当有更多其他性能隐患并发时所有的浏览器都哭了
回到刚才的例子我们可以用“事件委托”的方法来解决 这个因绑定事件随着按钮增加而可能导致的性能问题原理很简单利用 Javascript 的事件冒泡我们可以把事件的绑定从按钮移到它们的父级元素上不管按钮有多少它们只有一个共同的父级元素那样我们只需要绑定一次事件就可以了
代码如下
复制代码 代码如下:
var wrap = document
getElementById(
wrap
)
inputs = wrap
getElementsByTagName(
input
);
wrap
onclick = function (ev) {
var ev = ev || window
event
target = ev
target || ev
srcElement;
for (var i =
l = inputs
length; i < l; i++) {
if (inputs[i] === target) {
alert(i)
}
}
}
至此正餐完毕我们还可以再深入一下来些餐后甜点
除了在性能上事件委托比闭包的事件绑定更有优势以外事件委托还无需顾及子元素(即被绑定事件的元素)的数量比如我们在 onclick 事件绑定以后增加一个按钮
复制代码 代码如下:
var newInput = document
createElement(
input
);
newInput
setAttribute(
type
button
);
newInput
setAttribute(
value
按钮六
);
wrap
appendChild(newInput);
同 样在最后加了这段代码的闭包方式和事件委托方式我们可以看到闭包实现的事件绑定中点击“按钮六”毫无效果但是在事件委托中实现的事件绑定点击“按钮 六”则会有 alert相反如果我们要删除一个按钮闭包的方式仍会在内存中保存已删除按钮的 onclick 事件(除非手动设为 null)事件委托则不会对内存造成多余的负担就为这个原因我们也应该多加利用事件委托的方式来绑定同一层级的多个元素