浅谈JavaScript之事件绑定


Posted in Javascript onJuly 08, 2013

其实没有什么新的知识点,只是为了方便其他有需要的朋友们翻阅,对自己而言也算是一个积累,所以只能算是闲谈 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 相关文章推荐
JavaScript中的new的使用方法与注意事项
May 16 Javascript
javascript运动效果实例总结(放大缩小、滑动淡入、滚动)
Jan 08 Javascript
js实现有过渡渐变效果的图片轮播相册(兼容IE,ff)
Jan 19 Javascript
JSON 的正确用法探讨:Pyhong、MongoDB、JavaScript与Ajax
May 15 Javascript
用jquery获取自定义的标签属性的值简单实例
Sep 17 Javascript
Angular 2父子组件数据传递之@Input和@Output详解 (上)
Jul 05 Javascript
js实现数组和对象的深浅拷贝
Sep 30 Javascript
vue组件生命周期详解
Nov 07 Javascript
基于vue-cli创建的项目的目录结构及说明介绍
Nov 23 Javascript
基于Vue开发数字输入框组件
Dec 19 Javascript
Node.JS循环删除非空文件夹及子目录下的所有文件
Mar 12 Javascript
微信小程序获取地理位置及经纬度授权代码实例
Sep 18 Javascript
JS Map 和 List 的简单实现代码
Jul 08 #Javascript
利用JS实现浏览器的title闪烁
Jul 08 #Javascript
利用js实现遮罩以及弹出可移动登录窗口
Jul 08 #Javascript
使用jquery实现简单的ajax
Jul 08 #Javascript
从数据结构的角度分析 for each in 比 for in 快的多
Jul 07 #Javascript
JavaScript 上万关键字瞬间匹配实现代码
Jul 07 #Javascript
20行代码实现的一个CSS覆盖率测试脚本
Jul 07 #Javascript
You might like
一个好用的分页函数
2006/11/16 PHP
Fine Uploader文件上传组件应用介绍
2013/01/06 PHP
学习php中的正则表达式
2014/08/17 PHP
PHP实现Javascript中的escape及unescape函数代码分享
2015/02/10 PHP
微信公众号开发之通过接口删除菜单
2017/02/20 PHP
理解JavaScript的caller,callee,call,apply
2009/04/28 Javascript
JS 控制CSS样式表
2009/08/20 Javascript
为指定元素增加样式的js代码
2009/12/09 Javascript
jQuery的slideToggle方法实例
2013/05/07 Javascript
jQuery获取页面及个元素高度、宽度的总结——超实用
2015/07/28 Javascript
js仿黑客帝国字母掉落效果代码分享
2020/11/08 Javascript
Bootstrap入门书籍之(零)Bootstrap简介
2016/02/17 Javascript
js 原型对象和原型链理解
2017/02/09 Javascript
Vue.js与 ASP.NET Core 服务端渲染功能整合
2017/11/16 Javascript
three.js中文文档学习之通过模块导入
2017/11/20 Javascript
使用react实现手机号的数据同步显示功能的示例代码
2018/04/03 Javascript
Vue 实现手动刷新组件的方法
2019/02/19 Javascript
jQuery实现带3D切割效果的轮播图功能示例【附源码下载】
2019/04/04 jQuery
IDEA安装vue插件图文详解
2019/09/26 Javascript
解决python升级引起的pip执行错误的问题
2018/06/12 Python
Python爬取数据并写入MySQL数据库的实例
2018/06/21 Python
利用Pyhton中的requests包进行网页访问测试的方法
2018/12/26 Python
对python中矩阵相加函数sum()的使用详解
2019/01/28 Python
Python绘制二维曲线的日常应用详解
2019/12/04 Python
python函数enumerate,operator和Counter使用技巧实例小结
2020/02/22 Python
PYQT5 vscode联合操作qtdesigner的方法
2020/03/24 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
HTML5之SVG 2D入门7—SVG元素的重用与引用
2013/01/30 HTML / CSS
匡威英国官网:Converse英国
2018/12/02 全球购物
意大利网上药房:Farmacia 33
2020/01/27 全球购物
Currentbody美国/加拿大:美容仪专家
2020/03/09 全球购物
益达广告词
2014/03/14 职场文书
2015欢度元旦标语口号
2014/12/09 职场文书
探究Mysql模糊查询是否区分大小写
2021/06/11 MySQL
世界无敌的ICOM IC-R9500宽频接收机
2022/03/25 无线电
cypress测试本地web应用
2022/06/01 Javascript