深入理解DOM事件机制系列第三篇——事件对象
前面的话
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息。所有浏览器都支持event对象,但支持方式不同。本文将详细介绍事件对象
获取事件对象
【1】一般地,event对象是事件程序的第一个参数
[注意]IE8-浏览器不支持
//IE8-浏览器输出undefined,其他浏览器则输出事件对象[object MouseEvent]
<div id="box" style="height:30px;width:200px;background:pink;"></div>
<script>
var oBox = document.getElementById('box');
oBox.onclick = function(a){
box.innerHTML = a;
}
</script>
【2】另一种方法是直接使用event变量
[注意]firefox浏览器不支持
//firefox浏览器输出undefined,其他浏览器则输出事件对象[object MouseEvent]
<div id="box" style="height:30px;width:200px;background:pink;"></div>
<script>
var oBox = document.getElementById('box');
oBox.onclick = function(){
box.innerHTML = event;
}
</script>
兼容
于是,对于获取事件对象的常见兼容写法如下
<div id="box" style="height:30px;width:200px;background:pink;"></div>
<script>
var oBox = document.getElementById('box');
oBox.onclick = function(e){
e = e || event;
box.innerHTML = e;
}
</script>
属性和方法
事件对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都有些共有的属性和方法
事件类型
事件有很多类型,事件对象中的type属性表示被触发的事件类型
<div id="box" style="height:30px;width:200px;background:pink;"></div>
<script>
//鼠标移入时,显示mouseover;移出时,显示mouseout;点击时,显示click
var oBox = document.getElementById('box');
oBox.onclick = oBox.onmouseout =oBox.onmouseover =function(e){
e = e || event;
box.innerHTML = e.type;
}
</script>
通过点击或按tab键将焦点切换到button按钮上可以触发focus事件
<button id="box" style="height:30px;width:200px;background:pink;"></button>
<script>
var oBox = document.getElementById('box');
oBox.onfocus = function(e){
e = e || event;
box.innerHTML = e.type;
}
</script>
事件目标
关于事件目标,共有currentTarget、target和srcElement这三个属性
currentTarget
currentTarget属性返回事件当前所在的节点,即正在执行的监听函数所绑定的那个节点
[注意]IE8-浏览器不支持
一般地,currentTarget与事件中的this指向相同。但在attachEvent()事件处理程序中,this指向window,详细信息移步至此
<style>
.in{height: 30px;background-color: lightblue;margin:0 10px;}
</style>
<ul id="box">
<li class="in">1</li>
<li class="in">2</li>
</ul>
<script>
box.onclick = function(e){
e = e || event;
var tags = box.getElementsByTagName('li');
tags[0].innerHTML = e.currentTarget;
tags[1].innerHTML = (e.currentTarget === this);
}
</script>
target
currentTarget属性返回事件正在执行的监听函数所绑定的节点,而target属性返回事件的实际目标节点
[注意]IE8-浏览器不支持
以下代码中,点击该实际目标节点时,颜色变品红;移出时,颜色变浅蓝
<style>
#box{background-color: lightblue;}
.in{height: 30px;}
</style>
<ul id="box">
<li class="in">1</li>
<li class="in">2</li>
</ul>
<script>
box.onclick = function(e){
e = e || event;
e.target.style.backgroundColor = 'pink';
}
box.onmouseout = function(e){
e = e || event;
e.target.style.backgroundColor = 'lightblue';
}
</script>
srcElement
srcElement属性与target属性功能一致
[注意]firefox浏览器不支持
<style>
#box{background-color: lightblue;}
.in{height: 30px;}
</style>
<ul id="box">
<li class="in">1</li>
<li class="in">2</li>
</ul>
<script>
box.onclick = function(e){
e = e || event;
e.srcElement.style.backgroundColor = 'pink';
}
box.onmouseout = function(e){
e = e || event;
e.srcElement.style.backgroundColor = 'lightblue';
}
</script>
兼容
var handler = function(e){
e = e || event;
var target = e.target || e.srcElement;
}
事件代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation),也叫事件委托
事件代理应用事件目标的target和srcElement属性完成。利用事件代理,可以提高性能及降低代码复杂度
有一个需求,一个<ul>中有5个<li>,移入时变浅蓝,移出时变品红
下面分别用常规方法和事件代理方法来实现
<style>
#box{background-color: pink;}
.in{height: 30px;}
</style>
<ul id="box">
<li class="in">1</li>
<li class="in">2</li>
<li class="in">3</li>
<li class="in">4</li>
<li class="in">5</li>
</ul>
<script>
//常规方法
var tags = box.getElementsByTagName('li');
for(var i = 0; i < tags.length; i++){
tags[i].onmouseover = function(e){
this.style.backgroundColor = 'lightblue';
}
tags[i].onmouseout = function(e){
this.style.backgroundColor = 'pink';
}
}
</script> <script>
//事件代理方法
box.onmouseover = function(e){
e = e || event;
var target = e.target || e.srcElement;
target.style.backgroundColor = 'lightblue';
}
box.onmouseout = function(e){
e = e || event;
var target = e.target || e.srcElement;
target.style.backgroundColor = 'pink';
}
</script>
如果可行的话,也可以考虑为document添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件。这样做与采取传统的做法相比有以下优点:
1、document对象很快就可以访问,而且可以在页面生命周期的任何时间点上为它添加事件处理程序,而无需等待DOMContentLoaded或load事件。换句话说,只要可单击的元素呈现在页面上,就可以立即具备适当的功能
2、在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少
3、整个页面占用的内存空间更少,能够提升整体性能
最适合使用事件委托技术的事件包括click、mousedown、mouseup、keydown、keyup和keypress
下面封装一个可以使用事件委托的事件绑定函数
function bindEvent(elem,type,selector,fn){
if(fn == null){
fn = selector;
selector = null;
}
elem.addEventListener(type,function(e){
var target;
if(selector){
target = e.target;
if(target.matches(selector)){
fn.call(target,e);
}
}else{
fn(e);
}
})
}
事件冒泡
事件冒泡是事件流的第三个阶段,通过事件冒泡可以在这个阶段对事件做出响应
关于冒泡,事件对象中包含bubbles、cancelBubble、stopPropagation()和stopImmediatePropagation()这四个相关的属性和方法
bubbles
bubbles属性返回一个布尔值,表示当前事件是否会冒泡。该属性为只读属性
发生在文档元素上的大部分事件都会冒泡,但focus、blur和scroll事件不会冒泡。所以,除了这三个事件bubbles属性返回false外,其他事件该属性都为true
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
//点击按钮时,按钮内容为true,说明click事件默认可冒泡
test.onclick = function(e){
test.innerHTML =e.bubbles;//true
}
</script>
<div id="test" style="height: 50px;width: 200px;overflow:scroll;background:pink;line-height:60px;">内容</div>
<script>
//滚动时,div内容变成false,说明scroll事件默认不可冒泡
test.onscroll = function(e){
test.innerHTML =e.bubbles;//false
}
</script>
stopPropagation()
stopPropagation()方法表示取消事件的进一步捕获或冒泡,无返回值
[注意]IE8-浏览器不支持
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
//点击按钮时,按钮内容为'button',因为阻止了<button>向<body>的冒泡
test.onclick = function(e){
e = e || event;
e.stopPropagation();
test.innerHTML +='button\n';
}
document.body.onclick = function(e){
test.innerHTML += 'body\n'
}
</script>
stopImmediatePropagation()
stopImmediatePropagation()方法不仅可以取消事件的进一步捕获或冒泡,而且可以阻止同一个事件的其他监听函数被调用,无返回值
[注意]IE8-浏览器不支持
使用stopIPropagation()方法,可以阻止冒泡,但无法阻止同一事件的其他监听函数被调用
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
//使用stopIPropagation()方法,<button>内部变为'button',且背景颜色变成浅蓝
test.addEventListener('click',function(e){
e = e || event;
e.stopPropagation();
test.innerHTML +='button\n';
})
test.addEventListener('click',function(e){
e = e || event;
test.style.background = 'lightblue';
})
document.body.onclick = function(e){
test.innerHTML += 'body\n'
}
</script>
使用stopImmediatePropagation()方法,即可以阻止冒泡,也可以阻止同一事件的其他监听函数被调用
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
//使用stopImmediatePropagation()方法,<button>内部变为'button',且背景颜色不变
test.addEventListener('click',function(e){
e = e || event;
e.stopImmediatePropagation();
test.innerHTML +='button\n';
})
test.addEventListener('click',function(e){
e = e || event;
test.style.background = 'lightblue';
})
document.body.onclick = function(e){
test.innerHTML += 'body\n'
}
</script>
cancelBubble
cancelBubble属性只能用于阻止冒泡,无法阻止捕获阶段。该值可读写,默认值是false。当设置为true时,cancelBubble可以取消事件冒泡
[注意]该属性全浏览器支持,但并不是标准写法
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
test.onclick = function(e){
e = e || event;
e.cancelBubble = true;
test.innerHTML +='button\n';
}
document.body.onclick = function(e){
test.innerHTML += 'body\n'
}
</script>
当使用stopIPropagation()方法或stopImmediatePropagation()方法时,关于cancelBubble值的变化,各浏览器表现不同
//chrome/safari/opera中,cancelBubble的值为false
//IE9+/firefox中,cancelBubble的值为true
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
test.onclick = function(e){
e = e || event;
e.stopPropagation();
test.innerHTML = e.cancelBubble;
}
</script>
兼容
var handler = function(e){
e = e || event;
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
}
事件流
eventPhase
eventPhase属性返回一个整数值,表示事件目前所处的事件流阶段
0表示事件没有发生,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段
[注意]IE8-浏览器不支持
【1】以下代码返回2,表示处于目标阶段
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
test.onclick = function(e){
e = e || event;
test.innerHTML = e.eventPhase;
}
</script>
【2】以下代码返回1,表示处于捕获阶段
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
document.addEventListener('click',function(e){
e = e || event;
test.innerHTML = e.eventPhase;
},true);
</script>
【3】以下代码返回3,表示处于冒泡阶段
<button id="test" style="height: 30px;width: 200px;"></button>
<script>
document.addEventListener('click',function(e){
e = e || event;
test.innerHTML = e.eventPhase;
},false);
</script>
取消默认行为
常见的默认行为有点击链接后,浏览器跳转到指定页面;或者按一下空格键,页面向下滚动一段距离
关于取消默认行为的属性包括cancelable、defaultPrevented、preventDefault()和returnValue
使用
1、在DOM0级事件处理程序中取消默认行为,使用returnValue、preventDefault()和return false都有效
2、在DOM2级事件处理程序中取消默认行为,使用return false无效
3、在IE事件处理程序中取消默认行为,使用preventDefault()无效
点击下列锚点时,会自动打开博客园首页
<a id="test" href="http://www.cnblogs.com" target="_blank">链接</a>
cancelable
cancelable属性返回一个布尔值,表示事件是否可以取消。该属性为只读属性。返回true时,表示可以取消。否则,表示不可取消
[注意]IE8-浏览器不支持
<a id="test" href="#">链接</a>
<script>
test.onclick= function(e){
e = e || event;
test.innerHTML = e.cancelable;
}
</script>
preventDefault()
preventDefault()方法取消浏览器对当前事件的默认行为,无返回值
[注意]IE8-浏览器不支持
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick= function(e){
e = e || event;
e.preventDefault();
}
</script>
returnValue
returnValue属性可读写,默认值是true,但将其设置为false就可以取消事件的默认行为,与preventDefault()方法的作用相同
[注意]firefox和IE9+浏览器不支持
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick= function(e){
e = e || event;
e.returnValue = false;
}
</script>
兼容
var handler = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
}
return false
除了以上方法外,取消默认事件还可以使用return false
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick= function(e){
return false;
}
</script>
defaultPrevented
defaultPrevented属性表示默认行为是否被阻止,返回true时表示被阻止,返回false时,表示未被阻止
[注意]IE8-浏览器不支持
<a id="test" href="http://www.cnblogs.com">链接</a>
<script>
test.onclick= function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
test.innerHTML = e.defaultPrevented;
}
</script>
深入理解DOM事件机制系列第三篇——事件对象的更多相关文章
- 深入理解DOM事件机制系列第四篇——事件模拟
× 目录 [1]引入 [2]模拟机制 [3]自定义事件 前面的话 事件是网页中某个特别的瞬间,经常由用户操作或通过其他浏览器功能来触发.但实际上,也可以使用javascript在任意时刻来触发特定的事 ...
- 深入理解DOM事件类型系列第三篇——变动事件
× 目录 [1]删除节点 [2]插入节点 [3]特性节点[4]文本节点 前面的话 变动(mutation)事件能在DOM中的某一部分发生变化时给出提示,这类事件非常有用,但都只能使用DOM2级事件处理 ...
- 深入理解this机制系列第三篇——箭头函数
× 目录 [1]痛点 [2]解决 [3]基本用法[4]回调函数[5]注意事项 前面的话 this机制与函数调用有关,而作用域则与函数定义有关.有没有什么是可以将this机制和作用域联系起来的呢?本文将 ...
- 深入理解javascript函数进阶系列第三篇——函数节流和函数防抖
前面的话 javascript中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理,否则一般不会遇到跟性能相关的问题.但在一些少数情况下,函数的触发不是由用户直接控制的.在这些场景 ...
- 深入理解javascript选择器API系列第三篇——h5新增的3种selector方法
× 目录 [1]方法 [2]非实时 [3]缺陷 前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuer ...
- 深入理解javascript选择器API系列第三篇——HTML5新增的3种selector方法
前面的话 尽管DOM作为API已经非常完善了,但是为了实现更多的功能,DOM仍然进行了扩展,其中一个重要的扩展就是对选择器API的扩展.人们对jQuery的称赞,很多是由于jQuery方便的元素选择器 ...
- 深入理解脚本化CSS系列第三篇——脚本化CSS类
前面的话 在实际工作中,我们使用javascript操作CSS样式时,如果要改变大量样式,会使用脚本化CSS类的技术,本文将详细介绍脚本化CSS类 style 我们在改变元素的少部分样式时,一般会直接 ...
- 深入理解javascript函数系列第三篇——属性和方法
× 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...
- 深入理解javascript函数系列第三篇
前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...
随机推荐
- what do i get for?
有时候经常反思,做事究竟为了什么? 有时候,又无法解释,过去做的一些事情,是为了什么? 就像上小学时候明明挺到讨厌学习的,但上了初中后就开始玩命学习了 上高中时候认为自己真的是喜欢上学习了,上大学尼玛 ...
- hdu3549还是网络流
最后一次训练模板(比较熟练了) 接下来训练网络流的建图 #include <cstdio> #define INF 2147483647 int n,m,ans,x,y,z,M,h,t,T ...
- LintCode 77: 最长公共子序列
public class Solution { /** * @param A, B: Two string. * @return: the length of the longest common s ...
- 【DFS】POJ 1321
POJ 1321 棋盘问题 题意:中文题不解释. 思路:经典DP,比较取巧的想法是一行行(按照题目意思一行最多只能放一个)来看,标记一列列.注意考虑到有些行可能不放的情况. /** Sample In ...
- cocoapods
iOS 最新版 CocoaPods 的安装流程 1.移除现有Ruby默认源 $gem sources --remove https://rubygems.org/ 2.使用新的源 $gem sourc ...
- Salesforce练习Case
以下几个SFDC的Case基本覆盖了Force.com平台的一些基本操作流程,大家可以自己动手练习一下 Case 1: 在某公司的业务流程中,有零售店和销售人员两类信息,销售人员是指在零售店中工作的人 ...
- About_Smarty
Smarty是一个使用PHP写出来的模板PHP模板引擎,是目前业界最著名的PHP模板引擎之一.它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码 ...
- 步骤进度条 css
用css写一个简单的步骤进度条 html代码: <h4>南京游玩</h4> <ul class="step-list"> <li> ...
- Unity自动寻路Navmesh之入门
实例 我们要实现一个功能:点击场景中的一个位置,角色可以自动寻路过去.角色会绕过各种复杂的障碍,找到一条理论上”最短路径“. 步骤 1.创建地形 2.添加角色 3.创建多个障碍物,尽量摆的复杂一点,来 ...
- VS调试程序时一闪而过的问题-解决方法(网上搜集)
在VS2012里的控制台应用程序在运行时,结果画面一闪而过,不管是用F5 还是用Ctrl + F5都是一样,导致无法看到结果. 网上有不少的办法,说是都是在程序最后加一个要程序暂停的语句或从控制台上获 ...