深刻理解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>
相關文章
相關標籤/搜索