事件模块的演变(1)
本篇开始将回顾下Javascript的事件机制。同时会从一个最小的函数开始写到最后一个具有完整功能的,强大的事件模块。为叙述方便将响应函数/回调函数/事件Listener/事件handler都称为事件handler。
先看看页面中添加事件的几种方式
1,直接将JS代码写在HTML上
1 | < div onclick="alert(4);">Div1 Element</ div > |
HTML Element元素自身就拥有了很多onXXX属性,只需将JS代码赋值给其就可以了。赋值给onXXX的字符串将作为响应函数的函数体(FunctionBody
)。大概这是上世纪90年代的写法,那时候直接把JS代码写在网页中很普遍,也许那时候的JS并不太重要,只是用来做做验证或一些花哨的效果而已。
2,定义一个函数,赋值给html元素的onXXX属性
1 2 3 4 | < script type="text/javascript"> function clk(){} </ script > < div onclick="clk()">Div2 Element</ div > |
先定义函数clk,然后赋值给onclick属性,这种方式也应该属于上世纪90年代的流行写法。比第一种方式好的是它把业务逻辑代码都封装在一个函数里了,使HTML代码与JS代码稍微有点儿分离,不至于第一种那么紧密耦合。
3,使用element.onXXX方式
1 2 3 4 5 | <div id= "d3" >Div3 Element</div> <script type= "text/javascript" > var d3 = document.getElementById( 'd3' ); d3.onclick = function (){ } </script> |
这种方式也是早期的写法,但好处是可以将JS与HTML完全分离,前提是需要给HTML元素提供一个额外的id属性(或其它能获取该元素对象的方式)。
4,使用addEventListener或attachEvent
1 2 3 4 5 6 7 8 9 10 11 | <div id= "d4" >Div4 Element</div> <script type= "text/javascript" > var d4 = document.getElementById( 'd4' ); function clk(){alert(4)} if (d4.addEventListener){ d4.addEventListener( 'click' ,clk, false ); } if (d4.attachEvent){ d4.attachEvent( 'onclick' ,clk); } </script> |
这是目前推荐的方式,较前两种方式功能更为强大,可以为元素添加多个事件handler,支持事件冒泡或捕获,前三种方式默认都是冒泡。IE6/7/8仍然没有遵循标准而使用了自己专有的attachEvent,且不支持事件捕获。
好,把方式4简单的封装下, 兼容标准浏览器及IE浏览器。注意attachEvent的第一个参数需要加上个"on",addEventListener第三个参数为false表示事件冒泡,attachEvent没有第三个参数,默认就是冒泡,没有捕获。
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * * @param {Object} el HTML Element * @param {Object} type 事件类型 * @param {Object} fn 事件handler */ function addEvent(el, type, fn){ if (el.addEventListener){ el.addEventListener(type, fn, false ); } else { el.attachEvent( 'on' + type, fn); } } |
好,用这个工具函数添加一个给document添加一个点击事件
1 2 3 4 5 | function handler(){ alert( this ); alert(arguments[0]); } addEvent(document, 'click' , handler); |
在Firefox等标准浏览器中,点击页面后将弹出 “[object HTMLDocument]”,及handler中的this就是document自身。但在IE6/7/8中this却是window对象。这让人不爽,修改下与标准浏览器统一。
1 2 3 4 5 6 7 8 9 10 | function addEvent(el, type, fn){ if (el.addEventListener){ el.addEventListener(type, fn, false ); } else { el[ 'e' + fn] = function (){ fn.call(el, window.event); } el.attachEvent( 'on' +type, el[ 'e' +fn]); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端