淺談js之事件處理

上一篇是談的事件流,博客地址:點我;此次咱們說說具體的事件處理。javascript

0x00:事件處理程序html

如今有三種方式註冊事件處理程序:java

  • HTML事件處理程序
  • DOM0級事件處理程序
  • DOM2級事件處理程序

 001:HTML事件處理程序chrome

就是說給html標籤的屬性設置事件處理程序;例如:瀏覽器

<p onclick="alert('hello')">點我</p>

p標籤的屬性onclick,把它的值設置成javascript代碼字符串;這就是早期的js的用法app

如今這個方式,用的很少了,是由於HTML與JavaScript代碼耦合太緊密。就是說html代碼裏有javascript代碼,如今都講究行爲,樣式,結構分離;ide

還有就是這裏的javascript代碼字符串中的this,event對象是能夠直接使用的。例如:函數

<p onclick="console.log(this);console.log(event)">點我</p>

打印是這樣:this

這是由於當指定一串javascript代碼做爲HTML事件處理程序屬性值時,瀏覽器會把代碼字符串爲相似下面的函數中運行:url

function (event) {
    with(document) {
        with(this.form || {}) {
            with(this) {
                //這裏是代碼字符串
            }
        }
    }
}

這就解釋了爲何能直接使用event對象和this對象了。

可是還要注意有時咱們也這樣用

<body>
<p onclick="aa();">點我</p>
<script type="text/javascript">
function aa() {
    console.log(this);
    console.log(event);
}
</script>
</body>

這樣打印什麼呢?

這時候的this就是window對象,這就是this對象有的時候讓人很難肯定到底指的那個做用域。這這裏的函數就是window調用的;還有就是若是你想引用指向元素的做用域的this,你能夠向這個函數把這個this對象傳遞當參數過去,就像這樣:

<body>
<p onclick="aa(this)">點我</p>
<script type="text/javascript">
function aa(_this) {
    console.log(_this);
    console.log(event);
}
</script>
</body>
View Code

打印:

002:DOM0級事件處理程序

  就是說,首先獲取對這個元素DOM對象的引用,用DOM的getElementById()等這種方式獲取到對這個元素對象的引用,而後就是每一個事件都在這個對象上用相應的屬性,例如click事件,那麼這個對象就有一個onclick屬性與之對應,那你在這個對象的屬性上綁定事件處理程序,例obj.onclick = function() {//相應代碼};那麼當你在點擊的時候就會觸發事件了;

這種方式你們都太熟悉了我就不舉例了。

這種方式的優勢就是幾乎全部瀏覽器都兼容這種方式,通常不存在兼容性問題,咱們平時寫代碼如今也用的不少。簡單方便嘛。

可是他也是有缺點的。每一個事件元素目標對於每一個事件類型只能最多註冊一個事件處理程序。

例如:

obj.onclick = function () {
    //這裏是代碼1
};
obj.onclick = function () {
//這裏是代碼2
}

那麼後面的會覆蓋前面的,前面這個註冊程序就不會執行了。

這種事件處理的程序在事件流中只能會冒泡;以前的在事件流說過這個;

要是想刪除這個事件處理程序,就這樣:

obj.onclick = null;

 003:DOM2級事件處理程序

DOM2級事件定義了兩個方法,addEventListener()方法和removeEventListener()方法來處理和刪除事件處理程序。它們能夠接收三個參數,第一個參數:要處理的事件名,是一個字符串,可是要記得不要加「on」做爲前綴,第二個參數:做爲事件處理的函數,第三個參數:一個布爾值,這個布爾值爲true時,那就在事件捕獲階段調用事件處理程序,若是是false那就在冒泡階段調用事件處理程序。ps。這兩個方法支持除IE8及如下的其餘版本的全部瀏覽器

它的主要優勢是能夠爲同一個對象的同一個事件綁定多個事件處理程序。而且註冊的多個事件是按順序執行的;

上例子:

<p id="test">點我</p>
<script type="text/javascript">
var test = document.getElementById("test");
    test.addEventListener("click",function () {
        alert("first click");
    },false);
  
test.addEventListener("click",function () {
  alert("secend click");
  },false);
</script>

若是你想移除事件處理程序,你就須要用到removeEventListener()方法,它也接收三個參數,這三個參數要和你用addEventListener添加事件時的參數同樣,必需要如出一轍;而且若是addEventListener()的第二個參數,若是是匿名函數,那麼用removerEventListener()是刪除不了的;而且它也就只能處理用addEventListener註冊的事件,那麼用DOM0級註冊的事件是不能用它刪除的。

上離子:

test.addEventListener("click",fn,false);
test.removeEventListener('click',fn,false);

這樣就跟你沒有註冊事件似的;

可是若是你這樣:

test.addEventListener("click",fn,false);
test.addEventListener("click",fn,false);
test.addEventListener("click",fn,false);

卻只會彈出一個alert,而不是三個,這就是若是你使用相同的參數在同一對象調用屢次,處理程序只是註冊一次;

 IE永遠都是一朵奇葩,IE8及如下不支持,可是有兩個跟DOM2級的方法類似的事件處理方法,attachEvent()和detachEvent()方法。須要兩個參數,第一參數:事件名,注意要在事件名前加「on」,第二個參數:事件處理程序函數;它也是能夠綁定多個事件處理程序的;

這兩個方法支持IE5 ——IE10,IE11就再也不支持了;

我就說說他和標準DOM2級的不一樣,相同點就不提了,

  1.事件處理的做用域:

    不論是DOM0級仍是DOM2級他們的事件處理程序都是在它們所屬元素的的做用域中運行,可是attachEvent卻不是,事件處理程序會在全局做用域中運行,即事件處理程序中的this === window的,必定要記住這裏面的this是指向window的

  2.當調用多個事件處理程序時:

    第一點:當爲同一DOM對象同一個事件添加多個不一樣的事件處理程序函數時:在IE5-IE8,這個調用順序也很奇葩,後註冊的函數,先被調用,可是IE9,IE10這個順序就變過來了。

    第二點:當爲同一個DOM對象的同一個事件添加多個相同的事件處理程序函數時:在IE5——IE8是你添加幾個就執行幾個,可是在IE9,10卻不是這樣,它只會爲你註冊一個事件處理程序,即你添加多個執行一個;ps。可是你若是用匿名函數,其實每一個匿名函數都是不一樣的函數。即便你裏面的內容同樣。

因爲IE的這種奇葩,咱們想用DOM2級的方法,可是又要照顧IE8及如下,這就產生了一個跨瀏覽器的事件處理程序

 

//經過能力檢測來肯定瀏覽器支持
var EventUtil = {
    //param ele 元素對象
    //param type 事件類型
    //param handler 事件處理程序函數
    addHandler: function (ele,type,handler) {
        if(ele.addEventListener) {
            ele.addEventListener(type,handler,false);
        } else if (ele.attachEvent) {
            ele.attachEvent("on" + type,handler);
        } else {
            ele["on" + type] = handler;
        }
    },

    removeHandler: function (ele,type,handler) {
        if (ele.removeEventListener) {
            ele.removeEventListener(type,handler,false);
        } else if(ele.attachEvent) {
            ele.detachEvent("on" + type,handler);
        } else {
            ele["on" + type] = null;
        }
    }
}
跨瀏覽器事件處理程序

這個程序沒有考慮IE的attachEvent()函數的做用域問題,也就是說它裏面this不能用。但你能夠直接引用這個對象,或者用event對象的srcElement獲取到這個對象;

0x01 事件對象

在觸發DOM上的事件時就會自動產生一個事件對象,這個對象包含這個事件的相關信息。

  001.獲取event

就是直接在事件處理程序函數傳遞第一個參數就是event對象,這個是瀏覽器自動傳遞的。可是我今天親測了一下發現:

 

 

 

 

     DOM0

DOM2級(addEventListener方法)

attachEvent

(僅IE5IE10支持)

chrome

支持傳參;

也支持window.event

支持傳參;

也支持window.event

 

 

IE

支持傳參;

也支持window.event

(可是IE8及如下不支持傳參方式)

支持傳參;

也支持window.event

IE9-IE11支持下)

 

支持傳參;

也支持window.event

firefox

僅支持傳參;

 

僅支持傳參;

 

 

 

opera

支持傳參;

也支持window.event

支持傳參;

也支持window.event

 

 

我用的瀏覽器都是最新的;

可是通常爲了兼容性通常在用到的是時候這樣寫:

event = event || window.event;

002.取消默認操做行爲

好比a標籤只要你點擊就跳轉到href屬性值的url,要是你不想讓它跳轉,你就要阻止默認行爲;

DOM0級事件處理程序中的取消默認事件:方式1:在事件處理程序的函數中返回值設置爲false,這個全部瀏覽器都支持;

                   方式2:event對象的方法,這樣用:event.preventDefault()方法,可是這個只是一部分瀏覽器支持:chrome,opera,IE11;那就是說其餘的都不支持了;還有IE自家的returnValue屬性,event.returnValue = false;也可取消默認行爲,僅IE5-IE10支持;

總結:若是你想用,那你就用返回值這種方式,兼容性最好了。

DOM2級中:那就直接用event.preventDefault();可是IE的attachEvent中要取消默認行爲,要用event.returnValue = false;

003.阻止事件傳播(冒泡或捕獲)

DOM0級和DOM2級均可以用event對象的stopPropagation(),可是IE8及如下不支持;

IE8及如下能夠用事件對象的cancelBubble屬性,設置爲true就取消冒泡;

004.在介紹一個event對象的一個type屬性的用法:它指的是事件目標

在例子中說明:

function handler (evt) {
    switch(evt.type) {
        case "click": 
        //相應代碼
         console.log("clicked");
        break;
        case "mouseover":
        // 相應代碼
        console.log("mouseover");
        break;
        case "mouseout":
        //相應代碼
        console.log("mouseout");
        break;
    }
}
test.onclick = handler;
test.onmouseover = handler;
test.onmouseout = handler;
View Code

多了不解釋;

005.event中的屬性

不一樣的事件它的event對象所包含的屬性也會有所不一樣。

下列只是列出了每一個事件都會有的

屬性/方法 類型 讀/寫 說明
bubbles Boolean read 代表事件是否冒泡
cancelable Boolean read 代表是否能夠取消事件的默認行爲
currentTarget Element read 其事件處理程序當前正在處理事件的那個元素
defaultPrevented Boolean read 爲true表示已經調用了preventDafult()
detail Integer read 與事件相關的細節信息
eventPhase Integer read

代表調用事件處理程序的階段:1表示捕獲階段

2表示處於目標,3表示冒泡階段

preventDefault() Function read 取消事件的默認行爲。若是cancelable是true,則可使用這個方法
stopImmediatePropagation() Function read 取消事件的進一步冒泡或捕獲,同時阻止任何事件處理程序被調用
stopPropagation() Function read 取消事件的進一步捕獲或冒泡
target Element read 事件目標
trusted Boolean read 爲true表示事件是瀏覽器生成的,false表示是由開發人員生成的
type String read 被觸發的事件類型
view AbstractView read 與事件相關的抽象視圖

其實還有不少,好比鼠標事件還要有座標位置信息,如clientX,clientY,screenX,screenY等,可是在鍵盤事件中就沒有座標信息

IE中所共有的

屬性/方法 類型 讀寫 說明
cancelBubble Boolean read,write 默認爲false,可是將其設置爲true就取消事件的冒泡,(與DOM中的stopPropagation對應
returnValue Boolean read,write 默認爲true,設置爲false取消事件的默認行爲(與DOM的preventDefault)
srcElement Element read 事件目標(與DOM中的target對應)
type String read 被觸發的事件類型

 

 006.跨瀏覽器事件對象

 

var EventUtil = {
    getEvent:function (event) {
        return event ? event : window.event;
    },
    getTarget: function (event) {
        return event.target || event.srcElement;
    },

    preventDefault: function (event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    stopPropagation: function (event) {
        if(event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};
View Code

 

 若有不許或錯誤,歡迎指正!

參考:javascript高級程序設計;

   javasript權威指南;

相關文章
相關標籤/搜索