DOM的默認事件、事件模型、事件委託、阻止默認事件、冒泡事件的方式等。

原生JavaScript事件詳解:
http://www.cnblogs.com/iyangyuan/p/4190773.htmljavascript

DOM0,DOM2,DOM3事件,事件基礎知識入門

DOM0,DOM2,DOM3事件,事件基礎知識入門:http://www.cnblogs.com/diligenceday/p/4175721.html
[解惑]JavaScript事件機制:
http://www.cnblogs.com/hustskyking/p/problem-javascript-event.htmlphp

  事件是javascript和HTML交互基礎, 任何文檔或者瀏覽器窗口發生的交互, 都要經過綁定事件進行交互;
  事件有DOM0, DOM2和DOM3的區分(別問我怎麼少了一個DOM1, 也沒找到DOM1的信息啊,);css

  DOM0就是直接經過 onclick寫在html裏面的事件, 好比:html

<input onclick="alert(1)" />

  DOM2是經過addEventListener綁定的事件, 還有IE下的DOM2事件經過attachEvent綁定;
  DOM3是一些新的事件, 區別DOM3和DOM2的方法我感受是DOM3事件有分大小寫的,DOM2沒有;java

  事件流
  事件流
  
  IE的事件流是冒泡, 從裏面往上面冒, netscape是從外部元素往內部元素捕獲;
  而DOM2級的事件規定了事件流包含三個階段包括: 1:事件捕獲, 2:處於目標階段, 3:事件冒泡階段(IE8以及更早版本不支持DOM事件流);node

DOM0事件

事件模型在不斷髮展,早期的事件模型稱爲DOM0級別。web

DOM0事件模型,全部的瀏覽器都支持。直接在dom對象上註冊事件名稱,就是DOM0寫法.chrome

document.getElementById("test").onclick = function(e){};

意思就是註冊一個onclick事件。固然,它和這種寫法是一個意思:瀏覽器

document.getElementById("test")["onmousemove"] = function(e){};

  
基於DOM0的事件,對於同一個dom節點而言,只能註冊一個,後邊註冊的同種事件會覆蓋以前註冊的。接下來再說說this。事件觸發時,this就是指該事件在哪一個dom對象上觸發。想解除事件就至關簡單了,只須要再註冊一次事件,把值設成nullapp

var btn = document.getElementById("test");
        btn.onclick = function(e){
          alert("ok");
        };

原理就是最後註冊的事件要覆蓋以前的,最後一次註冊事件設置成null,也就解除了事件綁定。

  DOM0的事件具備極好的跨瀏覽器優點, 會以最快的速度綁定, 若是你經過DOM2綁定要等到JS運行, DOM0不用, 由於DOM0是寫在元素上面的;

DOM2事件

DOM2支持同一dom元素註冊多個同種事件。
DOM2新增了捕獲和冒泡的概念。
DOM2事件經過addEventListener和removeEventListener管理,固然,這是標準。

註冊事件時,一般使用捕獲或冒泡的。事件只會由於捕獲或者冒泡觸發一次.
addEventListener固然就是註冊事件,她有三個參數,分別爲:」事件名稱」, 「事件回調」, 「捕獲/冒泡」

obj.addEventListener("click", func, true); // 捕獲方式
    obj.addEventListener("click", func, false); // 冒泡方式

DOM2事件的冒泡和捕獲
事件名稱就不用多說了,相比DOM0,去掉了前邊的on而已。
事件回調也很好理解,事件觸發了總得通知你吧!回調時和DOM0同樣,也會默認傳入一個event參數,同時this是指觸發該事件的dom節點。
最後一個參數是布爾型,true表明捕獲事件,false表明冒泡事件。

<html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title></title>
            <meta charset="utf-8" />
            <style type="text/css"> #p { width: 300px; height: 300px; padding: 10px; border: 1px solid black; } #c { width: 100px; height: 100px; border: 1px solid red; } </style>
        </head>
        <body>
        <div id="p">
            parent
            <div id="c">
                child
            </div>
        </div>
        <script type="text/javascript"> var p = document.getElementById('p'), c = document.getElementById('c'); c.addEventListener('click', function () { alert('子節點捕獲') }, true); c.addEventListener('click', function (e) { alert('子節點冒泡') }, false); p.addEventListener('click', function () { alert('父節點捕獲') }, true); p.addEventListener('click', function () { alert('父節點冒泡') }, false); </script>
        </body>
        </html>

  這個依次會打出父節點捕獲,子節點捕獲,子節點冒泡和父節點冒泡,(注意:若是你在目標元素上改變綁定事件的順序, 這些事件可能就不按照捕獲和冒泡的順序來了,而是根據捕獲和冒泡的順序進行觸發 , 這個有解決方法,參考:) ==>>(葉小釵的東東)http://www.cnblogs.com/yexiaochai/p/3567597.html );

  捕獲的事件是按照順序執行的, 而冒泡的事件在有的瀏覽器中的按照順序執行有的按照相反的順序執行;
  說實話啊,事件捕獲沒啥用處;

  還有一點要注意的是:元素點擊裏面的this有問題哦, 在IE8和和IE8之前, 經過attachEvent綁定的事件裏面的this是window;

<html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title></title>
            <meta charset="utf-8" />
            <style type="text/css"> #p { width: 300px; height: 300px; padding: 10px; border: 1px solid black; } </style>
        </head>
        <body>
        <div id="p">
            p
        </div>
        <script type="text/javascript"> var p = document.getElementById('p'); p.attachEvent("onclick",function(){ alert(this); }) //在IE5678這個彈出的是window哦,這個要主要, 要讓this 指向這個元素經過apply或者call改變上下文 </script>
        </body>
        </html>

  chrome下有個getEventListeners能夠獲取元素綁定事件, 從小釵哪裏抄的,代碼以下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
</head>
<body>
<div id="d">ddssdsd</div>
  <script type="text/javascript"> var node = document.getElementsByTagName('*'); var d = document.getElementById('d'); d.addEventListener('click', function () { alert(); }, false); d.addEventListener('click', function () { alert('我是第二次'); }, false); d.onclick = function () { alert('不規範的綁定'); } d.addEventListener('click', function () { alert(); }, true); d.addEventListener('mousedown', function () { console.log('mousedown'); }, true); var evets = typeof getEventListeners == 'function' && getEventListeners(d); getEventListeners(d) </script>
</body>
</html>

——-這裏我試了下報錯:index_3.html:87 Uncaught ReferenceError: getEventListeners is not defined———chrome下——–直接調試中可用:
Chrome DevTools->console->getEventListeners(d);

  這個兼容問題常見的解決方法,通常來講夠用了:

<script>
     var eventUtil = {
        add : function(el, type, handler) {
            if(el.addEventListener) {
                el.addEventListener(type, handler, false);
            }else if( el.attachEvent ) {
                el.attachEvent("on"+type, handler);
            }else{
                el["on"+type] = handler;
            }
        },
        off : function(el, type, handler) {
            if( el.removeEventListener ) {
                el.removeEventListener(type, handler, false)
            }else if( el.detachEvent ) {
                el.detachEvent(type, handler);
            }else{
                el["on"+type] = null;
            }
        }
     };
    </script>

其實,事件觸發時,會默認傳入一個event對象,前邊提過了,這個event對象上有一個方法:stopPropagation,經過此方法,能夠阻止冒泡,這樣外層div就接收不到事件了。代碼以下:

var btn = document.getElementById("test");
var btnInner = document.getElementById("testInner");

btn.addEventListener("click", function(e){
  alert("ok1");
}, false);

btnInner.addEventListener("click", function(e){
  //阻止冒泡
e.stopPropagation();
  alert("ok");
}, false);

終於要說說怎麼解除事件了。解除事件語法:btn.removeEventListener(「事件名稱」, 「事件回調」, 「捕獲/冒泡」);
這和綁定事件的參數同樣,詳細說明下:

·  事件名稱,就是說解除哪一個事件唄。
      ·  事件回調,是一個函數,這個函數必須和註冊事件的函數是同一個。
      ·  事件類型,布爾值,這個必須和註冊事件時的類型一致。

也就是說,名稱、回調、類型,三者共同決定解除哪一個事件,缺一不可。

事件對象

  不管在DOM0仍是DOM2仍是DOM3中都會在事件函數中傳入事件對象;

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <meta charset="utf-8" />
        <style type="text/css"> #p { width: 300px; height: 300px; padding: 10px; border: 1px solid black; } </style>
    </head>
    <body>
    <div id="p">
        p
    </div>
    <script type="text/javascript"> var p = document.getElementById('p'); p.addEventListener("click",function(){ console.log(arguments[0]); }) </script>
    </body>
    </html>

  事件對象event下的屬性和方法:

由於各個瀏覽器的事件對象不同, 把主要的時間對象的屬性和方法列出來;
bubble :    代表事件是否冒泡
cancelable :  代表是否能夠取消冒泡
currentTarget : 當前時間程序正在處理的元素, 和this同樣的;
defaultPrevented: false ,若是調用了preventDefualt這個就爲真了;
detail: 與事件有關的信息(滾動事件等等)
eventPhase: 若是值爲1表示處於捕獲階段, 值爲2表示處於目標階段,值爲三表示在冒泡階段
target || srcElement: 事件的目標
trusted: 爲ture是瀏覽器生成的,爲false是開發人員建立的(DOM3)
type : 事件的類型
view : 與元素關聯的window, 咱們可能跨iframe;
preventDefault()    取消默認事件;
stopPropagation() 取消冒泡或者捕獲;
stopImmediatePropagation() (DOM3)阻止任何事件的運行;
//stopImmediatePropagation阻止 綁定在事件觸發元素的 其餘同類事件的callback的運行

IE下的事件對象是在window下的,而標準應該做爲一個參數, 傳爲函數第一個參數;
IE的事件對象定義的屬性跟標準的不一樣,如:
cancelBubble 默認爲false, 若是爲true就是取消事件冒泡;
returnValue 默認是true,若是爲false就取消默認事件;
srcElement, 這個指的是target, Firefox下的也是srcElement;

兩個誤區:

  1. 在同一個對象上註冊事件,並不必定按照註冊順序執行

這一點,從上面的例子能夠看出,你隨便打亂四個事件綁定的順序,結果通常不變!出現這樣結果的緣由是存在捕獲模式和冒泡模式。之因此如此是由於事件目的地節點既綁定了冒泡事件也綁定了捕獲事件,此時的執行順序按照綁定的前後順序執行(狀況比較少見)。

  1. event.stopPropagation();就是阻止事件的冒泡

這個表述不能說他錯誤,可是是不完整的,他除了阻止事件的冒泡,還阻止事件的繼續捕獲,簡而言之就是阻止事件的進一步傳播。

js中的事件委託:http://www.tuicool.com/articles/jQZj6zB

事件委託:

1,什麼是事件委託:通俗的講,事件就是onclick,onmouseover,onmouseout,等就是事件,委託呢,就是讓別人來作,這個事件原本是加在某些元素上的,然而你卻加到別人身上來作,完成這個事件。

也就是:利用冒泡的原理,把事件加到父級上,觸發執行效果。

好處呢:1,提升性能。

咱們能夠看一個例子:須要觸發每一個li來改變他們的背景顏色。

<ul id="ul">
  <li>aaaaaaaa</li>
  <li>bbbbbbbb</li>
  <li>cccccccc</li>
</ul>

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");

  for(var i=0; i<aLi.length; i++){
    aLi[i].onmouseover = function(){
      this.style.background = "red";
    }
    aLi[i].onmouseout = function(){
      this.style.background = "";
    }
  }
}

這樣咱們就能夠作到li上面添加鼠標事件。

可是若是說咱們可能有不少個li用for循環的話就比較影響性能。

下面咱們能夠用事件委託的方式來實現這樣的效果。html不變

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");

/* 這裏要用到事件源:event 對象,事件源,無論在哪一個事件中,只要你操做的那個元素就是事件源。 ie:window.event.srcElement 標準下:event.target nodeName:找到元素的標籤名 */
  oUl.onmouseover = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "red";
    }
  }
  oUl.onmouseout = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "";
    }
  }
}

好處2,新添加的元素還會有以前的事件。

咱們還拿這個例子看,可是咱們要作動態的添加li。點擊button動態添加li

如:

<input type="button" id="btn" />
<ul id="ul">
  <li>aaaaaaaa</li>
  <li>bbbbbbbb</li>
  <li>cccccccc</li>
</ul>

不用事件委託咱們會這樣作:

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");
  var oBtn = document.getElementById("btn");
  var iNow = 4;
  for(var i=0; i<aLi.length; i++){
    aLi[i].onmouseover = function(){
      this.style.background = "red";
    }
    aLi[i].onmouseout = function(){
      this.style.background = "";
    }
  }

  oBtn.onclick = function(){
    iNow ++;
    var oLi = document.createElement("li");
    oLi.innerHTML = 1111 *iNow;
    oUl.appendChild(oLi);
  }


}

這樣作咱們能夠看到點擊按鈕新加的li上面沒有鼠標移入事件來改變他們的背景顏色。

由於點擊添加的時候for循環已經執行完畢。

那麼咱們用事件委託的方式來作。就是html不變

window.onload = function(){
  var oUl = document.getElementById("ul");
  var aLi = oUl.getElementsByTagName("li");
  var oBtn = document.getElementById("btn");
  var iNow = 4;

  oUl.onmouseover = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "red";
    }
  }
  oUl.onmouseout = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    //alert(target.innerHTML);
    if(target.nodeName.toLowerCase() == "li"){
    target.style.background = "";
    }
  }
  oBtn.onclick = function(){
    iNow ++;
    var oLi = document.createElement("li");
    oLi.innerHTML = 1111 *iNow;
    oUl.appendChild(oLi);
  }
}

阻止默認事件

http://www.2cto.com/kf/201412/359961.html
  
有一些html元素默認的行爲,好比說a標籤,點擊後有跳轉動做;form表單中的submit類型的input有一個默認提交跳轉事件;reset類型的input有重置表單行爲。

若是你想阻止這些瀏覽器默認行爲,JavaScript爲你提供了方法。

先上代碼

var $a = document.getElementsByTagName("a")[0];
 $a.onclick = function(e){
     alert("跳轉動做被我阻止了")
     e.preventDefault();
     //return false;//也能夠
 }

默認事件沒有了。

既然return false 和 e.preventDefault()都是同樣的效果,那它們有區別嗎?固然有。

僅僅是在HTML事件屬性 和 DOM0級事件處理方法中 才能經過返回 return false 的形式組織事件宿主的默認行爲。

阻止冒泡事件:

function stopBubble(e){
  if(e&&e.stopPropagation){//非IE
   e.stopPropagation();
  }
  else{//IE
   window.event.cancelBubble=true;
  }
 }