深入理解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對象很快就可以訪問,而且可以在頁面生命周期的任何時間點上為它添加事件處理程序,而無需等待DOMContentLoadedload事件。換句話說,只要可單擊的元素呈現在頁面上,就可以立即具備適當的功能

  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>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM