其实没有什么新的知识点,只是为了方便其他有需要的朋友们翻阅,对自己而言也算是一个积累,所以只能算是闲谈 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 = 0, l = inputs.length; i < l; i++) {
    inputs[i].onclick = function () {
        alert(i);
    }
}

请问,这样执行的结果是什么?
/***************************分割线***************************/
如果你的回答是“点击按钮时, alert 当前按钮的索引值 i”,那你就中了我的圈套了。大家不妨试试,无论你点击哪个按钮,它都会alert(5)。

这个看似理所当然的结果为什么会和实际情况不同呢?其实也是很好理解的。
因为 onclick 只是事件绑定,而不是执行,当我们执行 onclick 事件的时候,这时的 i 已经是循环以后的值了,照这样看,每个按钮都alert(5) 也就不足为奇了。

那么,如果我们要怎么实现“点击按钮时,alert 当前按钮的索引值 i”呢?这里就要用到 JavaScript 中暗藏玄机的一个概念“闭包”。我们可以用闭包的方式改写以上 JS,把 for 循环中的 i 值保存在内存中,代码如下:
复制代码 代码如下:
var wrap = document.getElementById('wrap'),
    inputs = wrap.getElementsByTagName('input');

for (var i = 0, l = inputs.length; i < l; i++) {
    (function (cur) {
        inputs[cur].onclick = function () {
            alert(cur);
        }
    })(i)
}

再试试效果?确实能 alert 出相应的索引值了,不过至此为止还只是开胃菜,正题才刚刚开始!
以上的方法,我们是通过循环 + 闭包给 button 按钮上绑定事件,我们知道,在 JavaScript 中函数也是对象,对象就会占用内存,现在的例子中只有 5 个按钮,或许你会认为这样的性能开销可以忽略不计,但是如果当我们有 50个,甚至 500 个按钮的时候,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 = 0, 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),事件委托则不会对内存造成多余的负担,就为这个原因,我们也应该多加利用事件委托的方式来绑定同一层级的多个元素。
标签:
JavaScript,事件绑定

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
评论“浅谈JavaScript之事件绑定”
暂无“浅谈JavaScript之事件绑定”评论...

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。