一:事件与事件流
javascript
中的事件,可以理解就是在 HTML 文档或者浏览器中发生的一种交互操作,使得网页具备互动性,常见的有加载事件、鼠标事件、自定义事件等由于 DOM 是一个树结构,如果在父子节点绑定事件时候,当触发子节点的时候,就存在一个顺序问题,这就涉及到了事件流的概念 事件流都会经历三个阶段:
- 事件捕获阶段(
capture phase
) - 处于目标阶段(
target phase
) - 事件冒泡阶段(
bubbling phase
)
事件冒泡是一种从下往上的传播方式,由最具体的元素(触发节点)然后逐渐向上传播到最不具体的那个节点,也就是 DOM 中最高层的父节点。
<!D0CTYPE html><html lang="'en">
<head>
<meta charset="UTF-8">
<title>Event Bubbling</title>
</head>
<body>
<button id="clickMe">Click Me</button>
</body>
</html>
然后,我们给 button 和它的父元素,加入点击事件
var button =document.getElementById('clickMe');
button.onclick =function(){
console.log('1.Button');
};
document.body.onclick=function(){
console.log('2.body');
};
document.onclick=function(){
console.log('3.document');
};
window.onclick =function(){
console.log('4.window');
};
点击按钮,输出如下
1.button
2.body
3.document
4.window
点击事件首先在button
元素上发生,然后逐级向上传播事件捕获与事件冒泡相反,事件最开始由不太具体的节点最早接受事件,而最具体的节点(触发节点)最后接受事件
二:事件模型
事件模型可以分为三种:
- 原始事件模型(DOMO级)
- 标准事件模型(DOM2级)
- IE事件模型(基本不用)
2.1.原始事件模型
事件绑定监听函数比较简单,有两种方式:
- HTML代码中直接绑定:
<input type="button" onclick="fun()">
- 通过js代码绑定
var btn = document.getElementById('.btn');
btn.onclick = fun;
特性:
- 绑定速度快
DOMO 级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行
- 只支持冒泡,不支持捕获
- 同一个类型的事件只能绑定一次
<input type="button" id="btn" onclick="fun1()">
var btn= document.getElementById('.btn');
btn.onclick = fun2;
如上,当希望为同一个元素绑定多个同类型事件的时候(上面的这个 btn 元素绑定2个点击事件),是不被允许的,后绑定的事件会覆盖之前的事件。
删除 DOM0 级事件处理程序只要将对应事件属性置为null即可
btn.onclick = null;
2.2.标准事件模型
在该事件模型中,一次事件共有三个过程:
- 事件捕获阶段:事件从 document 一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行
- 事件处理阶段:事件到达目标元素,触发目标元素的监听函数
- 事件冒泡阶段:事件从目标元素冒泡到 document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行
事件绑定监听函数的方式如下:
addEventListener(eventType,handler,useCapture)
事件移除监听函数的方式如下:
removeEventListener(eventType,handler,useCapture)
参数如下:
- eventType 指定事件类型(不要加on)
- handler 是事件处理函数
- useCapture 是一个 boolean 用于指定是否在捕获阶段进行处理,一般设置为 false 与IE浏 览器保持一致
举个例子:
var btn = document.getElementById('.btn');
btn.addEventListener('click',showessage,false);
btn.removeEventListener('click',showessage,false);
特性
- 可以在一个D0M 元素上绑定多个事件处理器,各自并不会冲突
btn.addEventListener('click',showMessagel,false);
btn.addEventListener('click',showMessage2false);
btn.addEventListener('click",showMessage3,false);
执行时机 当第三个参数(useCapture
)设置为 true
就在捕获过程中执行,反之在冒泡过程中执行处理函数 下面举个例子:
<div id='div'>
<p id='p'><span id='span'>Click Me!</span></p>
</div>
设置点击事件
var div = document.getElementById('div');
var p= document.getElementById('p');
function onclickFn (event){
var tagName = event.currentTarget.tagName;
var phase = event.eventPhase;
console.log(tagName,phase);
}
div.addEventListener('click',onClickFn,false);
p.addEventListener('click',onClickFn,false);
上述使用了 eventPhase
,返回一个代表当前执行阶段的整数值。1为捕获阶段、2为事件对象触发阶 段、3为冒泡阶段
点击Click Me!,输出如下
P 3T
DIV 3C
可以看到,p
和 div
都是在冒泡阶段响应了事件,由于冒泡的特性,裹在里层的p 率先做出响应
如果把第三个参数都改为 true
div.addEventListener('click',onClickFn,true);
p.addEventListener('click',onClickFn,true);
输出如下
DIV 1
P 1
两者都是在捕获阶段响应事件,所以div比p标签先做出响应
2.3.IE事件模型
IE事件模型共有两个过程:
- 事件处理阶段:事件到达目标元素,触发目标元素的监听函数。
- 事件冒泡阶段:事件从目标元素冒泡到 document,依次检查经过的节点是否绑定了事件监听函数,如果有则执行
事件绑定监听函数的方式如下:
attachEvent(eventType,handler)
事件移除监听函数的方式如下:
detachEvent(eventType,handler)
举个例子:
var btn=document.getElementById('.btn');
btn.attachEvent('onclick',showMessage);
tn.detachEvent('onclick',showMessage);