深刻理解DOM事件机制系列第三篇——事件对象

前面的话

  在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着全部与事件有关的信息。全部浏览器都支持event对象,但支持方式不一样。本文将详细介绍事件对象html

 

获取事件对象

  【1】通常地,event对象是事件程序的第一个参数chrome

  [注意]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>

兼容this

  因而,对于获取事件对象的常见兼容写法以下spa

<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>

属性和方法

  事件对象包含与建立它的特定事件有关的属性和方法。触发的事件类型不同,可用的属性和方法也不同。不过,全部事件都有些共有的属性和方法firefox

事件类型

  事件有不少类型,事件对象中的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事件code

<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添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件。这样作与采起传统的作法相比有如下优势:

  一、document对象很快就能够访问,并且能够在页面生命周期的任什么时候间点上为它添加事件处理程序,而无需等待DOMContentLoadedload事件。换句话说,只要可单击的元素呈如今页面上,就能够当即具有适当的功能

  二、在页面中设置事件处理程序所需的时间更少。只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少

  三、整个页面占用的内存空间更少,可以提高总体性能

  最适合使用事件委托技术的事件包括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

使用

  一、在DOM0级事件处理程序中取消默认行为,使用returnValue、preventDefault()和return false都有效

  二、在DOM2级事件处理程序中取消默认行为,使用return false无效

  三、在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>
相关文章
相关标签/搜索