Javascript事件总结(一)
2014-04-19 · 1,226 chars · 7 min read
最近在项目中使用原生的 javascript,不依赖任何类库开发通用组件,发现真的是“成也 jQuery,败也 jQuery”。离开 jQuery 都不会写 js 代码了,一个组件花费的大部分时间,在使用 jQuery 的情况下都可以分分钟搞定。这其中问题比较大的一块就是 javascript 事件,下面认真总结一下。
事件流#
第一个要提的概念就是事件流。在很久很久以前,浏览器的开发团队遇到一个问题:当用户点击一个a
标签的时候,他是否也点击了p
标签?是否也点击了div
呢…
<body> <div> <p><a href='1095'>Javascript事件总结<a></p> </div> </body>
IE 和 Netscape 的团队在这个问题上的认识是一致的:用户的点击事件不止发生在a
标签上,也发生在p
div
…上。那么总要有个顺序吧?事件流就是描述这个顺序的。但是 IE 和 Netscape 提出了相反的事件流概念,IE 的事件冒泡和 Netscape 的事件捕获。
还拿上面的代码说,事件冒泡是由具体 元素逐级传播到不具体的节点。就是a
->p
->div
->body
->html
->Document
,所有现代浏览器都支持事件冒泡,IE9、chrome、firefox 还会传播到 window 对象(点击在线测试)。而事件捕获刚好相反,不具体的节点先接受事件,具体的事件后接受事件,它的用意是在事件到达预定目标之前捕获它,同样的,IE9、chrome、firefox 也是从 window 对象开始捕获的。
这两家浏览器厂商对着干,这时候我们的“规范”就要跳出来统一他们了,“DOM2 级事件”规范规定的事件流包含 3 个阶段:事件捕获阶段,处于目标元素的阶段和事件冒泡阶段,他们依次发生。但是规范只是规范,实际情况是,IE8 以及更早的版本不支持 DOM2 级事件,IE9、chrome、FireFox 会在捕获和冒泡两个阶段涉及目标元素,所以目标元素的事件有两次被触发的机会。
事件处理程序#
click,load 之类的是事件,那么响应事件的函数就是事件处理程序。为事件指定处理程序的方式有:HTML 事件处理程序,DOM0 级事件处理程序,DOM2 级事件处理程序,IE 事件处理程序。
HTML 事件处理程序#
代码如下:
<input type="button" value="Click Me" onclick="alert('click')" />
onclick 执行的函数封装了event
变量,可以直接访问事件对象。而this
就是事件的 目标元素。例如:
<input type="button" value="Click Me" onclick="alert(event.type)" /> <input type="button" value="Click Me" onclick="alert(this.value)" />
onclick 后面这个动态创建的函数,可以直接访问 document 以及该元素本身的成员,如果当前元素是表单的一部分,还可以直接访问表单元素,因为它使用with
扩展了作用域。
function (){ with(document){ with(this.form){ with(this){ //... } } } }
使用示例:
<form> <input type="text" name="username" /> <input type="button" value="click" onclick="alert(username.value)" /> </form>
直接使用username.value
就可以访问好 name 为 username 的文本框的值,在线测试。
DOM0 级事件处理程序#
代码如下:
var btn = document.getELementById('myBtn') btn.onclick = function () { alert('click') }
DOM0 级事件处理程序被当做是元素的方法,所以可以this
使用访问到元素的属性,例如用this.id
访问 ID。DOM0 级事件处理程序会在事件流的冒泡阶段被处理(第一个例子中就使用了 DOM0 级事件处理程序)。另外,也可以通过设置为null
来删除。
DOM2 级事件处理程序#
DOM2 级事件定义了两个方法,用来添加和删除处理程序:addEventListener()
和removeEventListener()
。接受三个参数:要处理的事件名,作为事件处理程序的函数和一个表示事件阶段的布尔值(true-事件捕获阶段,false-事件冒泡阶段)。这个很经常用就不多说了,只要注意 IE9+才支持就好了,有问题欢迎留言交流。
IE 事件处理程序#
IE 实现了与 DOM 类似的两个方法,:attachEvent()
和detachEvent()
,因为 IE8 只支持事件冒泡,所以这两个方法只有两个参数。例如:
var btn = document.getElementById('btn') btn.attachEvent('onclick', function () { alert(1) })
注意它的第一个参数是“onclick”,不是“click”。还有一点就是 this 不是当前元素,而是 window。
跨浏览器的事件处理程序#
最后给出跨浏览器的解决方案:
function addHandler(element, type, handler) { if (element.addEventListener) { element.addEventListener(type, handler, false) } else if (element.attachEvent) { element.attachEvent('on' + type, handler) } else { element['on' + type] = handler } }
移除事件的兼容方案同理,我比较懒就不写了。