事件概述
事件是javascript和HTML交互基础, 任何文档或者浏览器窗口发生的交互, 都要通过绑定事件进行交互;
事件响应是异步处理的
事件响应是异步处理的, 当某个事件触发时,不一定马上会得到响应,而是异步处理的,响应的时间是不一定的。
事件的分类
DOM0/原始 事件模型
- 所有的浏览器都支持
- 绑定速度最快,直接写在元素上
- 只能绑定一个handler
- 没有冒泡还是捕获之说
- handler中获取event对象各浏览器差异
- 删除 element.on+event = null;
<!-- DOM0 绑定的方法 -->
<a id="foo" href="javascript;" onclick="alert('did stuff inline');">Click me</a>
<script type="text/javascript">
// HTML 中的 onclick="" 属性 和 element.onclick 等同
document.getElementById('foo').onclick = fucntion(){
alert('did stuff inline');
}
</script>
DOM2/标准 事件模型
IE事件模型(>=IE9,同时也支持标准事件模型)
标准事件模型与IE的事件模型的区别
| 选项 |
标准事件模型 |
IE事件模型(IE9之前) |
| 支持冒泡和捕获 |
都支持 |
只支持冒泡 |
| 绑定方法 |
addEventListener |
attachEvent(ie5及+) |
| 解绑方法 |
removeEventListener |
detachEvent(ie5及+) |
| 事件的名称参数 |
事件名字,例如click |
on+事件名字,例如onclick |
| 事件hanlde中对事件对象的获取 |
事件处理函数的第一个参数或window.event(FF不支持) |
通过window.event或事件处理函数的第一个参数 |
| 事件hanlde中的this |
事件绑定的对象 |
window |
| 阻止冒泡的方法 |
event.stopPropagation(); |
event.cancelBubble = true; |
| 阻止默认行为的方法 |
event.preventDefault(); |
event.returnValue = false; |
| 事件target |
event.target |
event.srcElement |
| 事件relatedTarget |
event.relatedTarget |
event.fromElement/event.toElement |
| 冒泡过程中currentTarget |
event.currentTarget |
无 |
| 单个元素添加多个事件处理程序,执行的顺序 |
执行顺序按照它们添加的顺序执行 |
执行顺序按照添加的顺序相反的顺序执行 |
-
支持冒泡和捕获
-
绑定方法
- addEventListener
- attacthEvent
var eventUtil = {
on : function(el, type, handler) {
if(el.addEventListener) {
el.addEventListener(type, handler, false);
}else if( el.attachEvent ) {
el.attachEvent("on"+type, handler);
}else{
el["on"+type] = handler;
}
},
off : function(el, type, handler) {
if( el.removeEventListener ) {
el.removeEventListener(type, handler, false)
}else if( el.detachEvent ) {
el.detachEvent(type, handler);
}else{
el["on"+type] = null;
}
}
};
-
解绑方法
- removeEventListener
- detachEvent
-
事件的名称参数
- 事件名字,例如click
- on+事件名字,例如onclick
-
事件hanlde中对事件对象的获取
- 支持标准事件模型的浏览器,不管用addEventListener还是ele.onclick方式绑定事件,通过事件处理的handle函数第一个参数就可以获取event对象;
- 而IE不支持标准事件模型的浏览器(<IE9),ele.onclick方式绑定事件时,只能用window.event来获取
function handle(event){
var event = event || window.event;
//...
}
ele.attachEvent && ele.attachEvent("onclick", handler);
ele.addEventListener && ele.addEventListener("click", handler, false);
ele.onclick = handler;
-
事件hanlde中的this
- addEventListener绑定事件的handle中的this指向被绑定的元素ele
- attacthEvent绑定事件的handle中的this指向window,而不是被绑定的元素ele
-
阻止冒泡的方法
- event.stopPropagation();
- event.cancelBubble = true;
function handle(event){
var event = event || window.event;
if(event.stopPropagation){
event.stopPropagation();
}else
{
event.cancelBubble= true;
}
//...
}
-
阻止默认行为的方法
- event.preventDefault();
- event.returnValue = false;
function handle(event){
var event = event || window.event;
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
//...
}
-
事件target
- event.target
- event.srcElement
function handle(event){
var event = event || window.event;
var target = event.target || event.srcElement;
//...
}
-
事件的relatedTarget
- relatedTarget
- fromElement/toElement
function handle(event){
var event = event || window.event;
var relatedTarget = event.relatedTarget || event.fromElement/*toElement*/;
//...
}
事件对象的其他参数
冒泡和捕获

冒泡带来的便利和不便
- 通过冒泡机制来实现事件代理
- 冒泡对某些事件的处理带来困扰例如mouseover/mouseout
事件代理
因为事件有冒泡机制,所有子节点的事件都会顺着父级节点跑回去,所以我们可以通过监听父级节点来实现监听子节点的功能,这就是事件代理。
使用事件代理主要有两个优势:
- 减少事件绑定,提升性能。之前你需要绑定一堆子节点,而现在你只需要绑定一个父节点即可。减少了绑定事件监听函数的数量。
- 动态变化的 DOM 结构,仍然可以监听。当一个 DOM 动态创建之后,不会带有任何事件监听,除非你重新执行事件监听函数,而使用事件监听无须担忧这个问题。
不能冒泡的事件
-
focus/blur事件不冒泡,但focusin and focusout Fire at the same time as focus and blur会冒泡。
from
-
mouseenter/mouseleave(only ie/opera 支持)不冒泡,在mouseover/mouseout时触发会冒泡
-
submit/reset事件
功能:监听表单的提交/重置;
在IE6到IE8下只会冒泡到当前提交表单所在的form标签中,也就说document下直接代理监听多个表单提交会有兼容性问题。
-
change事件
功能:监听元素value值的改变,input和select 在blur才触发;
change事件在IE6到IE8,chrome,safari下都不会冒泡,也不能像focus和blur一样可以用focusin和focusout替代,在IE下也不能通过设置captrue实现对事件的捕获,其他高级浏览器下可以。
-
select事件
功能:监听文本域中文字的选中。
select事件在IE6到IE8,chrome,safari下都不会冒泡,但是比change好的一点是,在IE下可以使用selectstart替代,而在高级浏览器中可以直接设置captrue为捕获即可。
键盘事件
键盘事件的触发流程
一个典型的按键输入,依次触发的事件依次是
- keydown
- keypress
- keypress事件触发后,input元素更新value属性
- keyup
如果一个按键被按下并重复按下,则可能在keydown和keyup事件之间触发多个keypress事件。
键盘事件的兼容性
| 选项 |
其他浏览器 |
IE |
| 不能打印的功能按键(退格,回车,escape)和箭头方向键,翻页键,F1-F12 |
有时候会触发keypress事件 |
IE只有当按键有一个ASCII码的时候,才会触发keypress |
| 获取按键码的事件属性 |
keyeCode/charCode |
keyCode |
| keydown/keyup |
keyeCode为虚拟按键码/charCode为0 |
keyCode为虚拟按键码 |
| keypress |
keyeCode为虚拟按键码/charCode为虚拟按键码,FF为0 |
keyCode为字符的ASCII值 |
| 输入中文时 |
不触发keypress,大部分浏览器触发keydown,keycode为229 |
不触发keypress,触发keydown,keycode为229 |
常见案例
- 过滤输入框的字符只能输入特定的字符
- 搜索框的suggest
鼠标事件的触发流程
一个典型的鼠标拖动操作,依次触发的事件依次是
- mouseover
- mousedown
- mousemove
- mouseup
- click
- mouseout
如果中间鼠标移动,将会触发多个mousemove事件。
鼠标事件的问题
jQuery/zepto的事件绑定
//绑定
$(ele).on( events [, selector ] [, data ], handler );
//触发事件
$(elementA).trigger( events );
事件概述
事件响应是异步处理的
事件的分类
DOM0/原始 事件模型
DOM2/标准 事件模型
IE事件模型(>=IE9,同时也支持标准事件模型)
标准事件模型与IE的事件模型的区别
支持冒泡和捕获
绑定方法
解绑方法
事件的名称参数
事件hanlde中对事件对象的获取
事件hanlde中的this
阻止冒泡的方法
阻止默认行为的方法
事件target
事件的relatedTarget
事件对象的其他参数
冒泡和捕获
冒泡带来的便利和不便
事件代理
因为事件有冒泡机制,所有子节点的事件都会顺着父级节点跑回去,所以我们可以通过监听父级节点来实现监听子节点的功能,这就是事件代理。
使用事件代理主要有两个优势:
不能冒泡的事件
focus/blur事件不冒泡,但focusin and focusout Fire at the same time as focus and blur会冒泡。
from
mouseenter/mouseleave(only ie/opera 支持)不冒泡,在mouseover/mouseout时触发会冒泡
submit/reset事件
功能:监听表单的提交/重置;
在IE6到IE8下只会冒泡到当前提交表单所在的form标签中,也就说document下直接代理监听多个表单提交会有兼容性问题。
change事件
功能:监听元素value值的改变,input和select 在blur才触发;
change事件在IE6到IE8,chrome,safari下都不会冒泡,也不能像focus和blur一样可以用focusin和focusout替代,在IE下也不能通过设置captrue实现对事件的捕获,其他高级浏览器下可以。
select事件
功能:监听文本域中文字的选中。
select事件在IE6到IE8,chrome,safari下都不会冒泡,但是比change好的一点是,在IE下可以使用selectstart替代,而在高级浏览器中可以直接设置captrue为捕获即可。
键盘事件
键盘事件的触发流程
一个典型的按键输入,依次触发的事件依次是
如果一个按键被按下并重复按下,则可能在keydown和keyup事件之间触发多个keypress事件。
键盘事件的兼容性
常见案例
键盘事件的兼容性列表
鼠标事件
鼠标事件的触发流程
一个典型的鼠标拖动操作,依次触发的事件依次是
如果中间鼠标移动,将会触发多个mousemove事件。
鼠标事件的问题
mousedown/mouseup不一定都会触发
当按下鼠标进入目标或按下鼠标移出目标区域
mouseover和mouseout的冒泡问题
适当的用mouseenter和mouseleave替代mouseover和mouseout
jQuery/zepto的事件绑定