Javascript事件模型系列(四)我所理解的javascript自定義事件

  被我拖延了將近一個月的javascript事件模型系列終於迎來了第四篇,也是我計劃中的最後一篇,說來太慚愧了,原本計劃一到兩個星期寫完的,誰知中間遇到了不少事情,公司的我的的,搞的本身心煩意亂浮躁了一段時間,好在最近這些事情都一件件趨於平息,我也有了精力繼續寫文章。javascript

  這個自定義事件實際上是挺讓我糾結的,首先本身平時從未使用過,只是有一次遇到一個問題有人指點說能夠用自定義事件,纔對這個東西有了印象。在網上搜「javascript自定義事件」,發現也有很多文章在寫,不過說實話讓我佩服的卻一篇也沒找到,就連張鑫旭大哥寫的漫談javascript自定義事件也把我看的雲裏霧裏。陸續查閱了一些資料後愈加以爲自定義事件這個東西真是個雞肋,沒什麼用武之地。這也使我一度想放棄寫這篇文章,但後來本身又進行了一些思考,並有了一些新的想法,因此在此仍是寫出來與你們分享。原本想大手一揮書寫標題「javascript自定義事件」,轉而一想這個標題真是被用濫了,滿大街走的都是長一個樣的,誰能認得我呀,親,我跟他們可真的不太同樣哦。因此前面加上了「我所理解的」,並不全是爲標題突出,其實真的有不少本身的理解。html

1、什麼是自定義事件

  這個其實並不難理解,js中有不少的事件,如click(單擊)、dbclick(雙擊)、mouseover(鼠標移上)等等,大部分是一些鼠標或鍵盤事件,固然也還有其餘的如文檔的load,只不過咱們平時更加關注前者,由於畢竟是要和用戶打交道嘛,這些能夠統稱爲DOM事件(都是發生在DOM元素上)。何爲自定義DOM事件呢?舉個栗子:元素有單擊、雙擊事件,我如今想定義一個三擊事件,即元素被連續點擊了三次,就給它起名字叫tripleclick。這就是一個自定義的事件。再來個栗子:元素的內部html發生變化,我想監聽到此事件,因而能夠定義一個htmlchange事件。概念就是這麼回事。java

  既然有DOM事件,那有沒有非DOM事件呢?動腦筋想想。有了~前段時間恰好研究過history API,其中點擊了瀏覽器後退按鈕會觸發popstate事件,這就是個非DOM事件。那咱們能夠自定義些什麼非DOM事件呢?再開闊一下思惟,javascript好歹也是一門編程語言呀,除了操做DOM、BOM以外還有不少事情能夠作呢。好比我寫了一個dog對象,也能夠給它自定義個事件bark(狗叫),一旦發生了這個事件,咱們能夠捕捉到,在onbark處理函數中執行一些操做,如把dog給趕走。node

  那麼,所謂自定義事件就是起個名字?這就完了?先埋個伏筆,後面來談談個人見解。編程

2、如何自定義事件

  關於實現自定義事件的方式,我搜索中文的網頁大概也就兩種方式,並且就是那麼幾篇文章被抄來抄去,實在是乏味。總結一下:設計模式

  第一種方式是本身模擬一個事件結構,其原理是這樣的,咱們平時監聽事件的時候其實就是一種觀察者模式,舉個例子吧更明確些。瀏覽器

<input type="button" value="點我" onclick="clickhandler()" />
<script type="text/javascript">
function clickhandler(){
    alert('點你怎麼了!');
}
</script>

  在這裏被觀察的主體就是這個button,有一個handler訂閱了它的點擊事件,當被點擊時,button會發布本身被點擊的消息,handler接收到消息便開始執行處理函數。是至關標準的一個觀察者模式。框架

  照着這個思路,咱們能夠把整個過程用代碼模擬出來,而不使用瀏覽器的事件機制,讓這個button發佈一點其餘的消息,好比咱們霸氣的「三擊」,而後寫一個handler來監聽這個三擊事件便可。具體的實現例子我就不寫了,由於我以爲這個模擬的辦法簡直是太土了,根本拿不上臺面,想研究的能夠看下這篇文章http://www.jb51.net/article/33697.htm 儘管我很噁心腳本之家這種隨便剽竊別人文章的行爲,但抱歉我真的找不到出處了。。。dom

  看過了第一種土的掉渣的方式,咱們再來看看高端洋氣的寫法。說白了,其實w3c已經定義了標準的自定義事件寫法了。編程語言

  第二種方式以下:

var e = document.createEvent('Event');//建立一個Event對象e
e.initEvent('myevent',true,true);//進行事件初始化
var d1 = document.getElementById('d1');//獲取DOM元素
d1.addEventListener('myevent',function(event){
    alert(‘我監聽到了自定義事件’+event.type);
},false);//綁定監聽器
d1.dispatchEvent(e);//觸發該事件

  使用標準方法仍是至關簡單的,首先利用document的createEvent方法能夠建立一個事件對象,createEvent接收一個參數表示事件的構造器,如Event、MouseEvent、UIEvent、CustomEvent,至於這些事件類都有哪些這裏就不詳細講了,你能夠查看我以前寫的系列,有提到相關內容能夠追蹤連接。而後使用initEvent函數進行事件的初始化,接收的參數分別表示事件的類型、是否冒泡、是否能夠用preventDefault()函數禁止默認行爲,在這裏你就能夠爲自定義事件起名字了。而後咱們註冊監聽器並觸發事件,這樣d1便能監聽到本身定義的事件了,ok,就這麼簡單!

  原本自定義事件的方式就該到此結束了,一個小小的意外,我搜到了一篇國外的文章,看到了以下字樣:

  來自mozilla開發者官網,說的就是上面的第二種方式。deprecated?啥意思?google之,藐視的意思!這種方式已經被藐視了哇!居然還在國內的各網站中被轉來轉去,國外的同仁正在藐視咱們。。。不能忍!趕快看看如今都用什麼方式了。

  第三種:

var event = new CustomEvent('build', { 'detail': elem.dataset.time });//區別就在這裏~
elem.addEventListener('build', function (e) { ... }, false);
elem.dispatchEvent(event);

  原來是直接建立Event對象,取代了原來的document.createEvent(),並且事件的初始化工做也在這裏完成了,沒必要調用initEvent()了。嗯~不錯,是能省一行代碼。探討爲何要這麼寫也沒什麼意義,咱跟着國際潮流走就是了。如今已經愈來愈明顯,這個所謂的自定義事件,其實與其餘事件是同宗同源,只是名字(類型)不一樣罷了。

3、自定義事件實例

  瞭解了這麼多,你確定也和我同樣還在困惑,上面的東西都是紙上兵法,這自定義事件到底怎麼用我仍是不知道。好比我就想要一個tripleclick(三擊)事件,具體該如何實現呢?下面就來實踐一下,GO~

  自定義事件的步驟我總結爲「三板斧」,下面開始操練:

  ①   建立自定義事件

var e = new CustomEvent('tripleclick',{'detail':'somemsg'});//建立自定義事件tripleclick

  ② 在合適的時機觸發事件

var counter = 0;
var d1 = document.getElementById('d1');
d1.onclick = function(){
    setTimeout(function(){counter=0;},500);
    if(++counter==3){
        d1.dispatchEvent(e);
    }
}

  其實這第二步纔是實現tripleclick事件的核心,首先聲明一個計數器,每次元素點擊便自增,當累計點擊三次的時候將事件派發出去,即觸發事件。爲了防止每次點擊之間的間隔時間過長,每次點擊後由一個延時函數進行清零,保證只有是連續點擊才觸發。代碼不難理解。我也想在這裏說說個人見解,自定義事件不僅僅是起個自定義名字,還要給這個事件加以描述,定義好它是在什麼樣的狀況下發生

  在這裏,tripleclick是依賴於click的,看上去更像是一個邏輯事件,非真正的事件。但因爲咱們的對象確實是CustomEvent的實例,那它便無疑是一個貨真價實的自定義事件。你可能會擔憂難道咱們的自定義事件都要依賴於現有的事件?其實也未必,稍後會寫另一個例子來講明。

  ③   爲事件註冊監聽函數

d1.addEventListener('tripleclick',function(event){
    alert(‘我被三擊了~’);
},false);

  在此處就能夠把咱們定義的tripleclick光明正大的寫在addEventListener函數中了。

  所有步驟就這些,完整的代碼以下:

<div id="d1">有本事點我三次</div>

<script type="text/javascript">
var d1 = document.getElementById('d1');
d1.addEventListener('tripleclick',function(event){
    alert('我被三擊了~');
},false);

var e = new CustomEvent('tripleclick',{'detail':'somemsg'});

var counter = 0;
d1.onclick = function(){
    setTimeout(function(){counter=0;},500);
    if(++counter==3){
        d1.dispatchEvent(e);
    }
}
</script>

  你能夠輕輕抖動三下手指,點擊下面這個囂張的div:

有本事點我三次

  有點感受了吧~不過這個三擊確實有點小兒科,實際上能派上用場的機率基本爲0,下面就來整點有用的東西,咱們來實現一個htmlchange事件,即元素的內部html發生變化時觸發該事件。這個東西在平時或許還真能用得着。

  首先,事件的建立和監聽與上面基本同樣

var e2 = new CustomEvent('htmlchange',{'detail':'somemsg'});
d1.addEventListener('htmlchange',function(event){
    alert('檢測到html發生變化!');
},false);

  而後,咱們須要採用一個定時函數來不斷檢測d1內部的html,當發現與舊值不一樣時便派發htmlchange事件,代碼以下:

var oldhtml = d1.innerHTML;
setInterval(function(){
        if(d1.innerHTML!==oldhtml){
            d1.dispatchEvent(e2);
       oldhtml = d1.innerHTML;
        }
},100);

  三板斧完畢,來看看效果:

我得兒意的飄~

  最慢能在0.1s內做出反應,你也能夠把時間設置的更小一些。咱們構想一個場景,你寫的一個子頁面A要被別人的頁面B嵌套,而且B會修改A頁面中某個元素的內部html,A在無權干涉B中代碼的狀況下,就能夠在本身頁面中定義一個htmlchange事件,監聽B對A的修改並做出處理。怎麼樣,體會到自定義事件的威力了吧。

4、談談自定義事件的用武之地

  看了不少紙上談兵的介紹以後我就一直在想,自定義事件的研究和使用爲什麼如此少?它的真正用處到底在哪裏?難道真的是javascript中的雞肋?

  在第三節舉出的兩個實例或許能說明一點什麼,至少它能幫咱們擴展一下DOM事件,在當前已有的事件不能知足需求時,能夠本身定義一個來使用。其餘的用途呢?此時我想到了開篇提到的觀察者模式,咱們認爲瀏覽器對事件的處理是一種觀察者模式,若是反過來呢,我想設計一種觀察者模式,是否能夠用自定義事件來實現呢?主體須要發佈的各類消息經過建立各類自定義事件來實現,對於消息的訂閱則經過註冊監聽器來實現,豈不是利用現有資源便完成了一個觀察者模式,而沒必要再寫那麼多的代碼去模擬。到這裏我又不由自主的想到了node.js,在node中,用事件驅動來完成代碼邏輯,其事件是否跟這裏的自定義事件一模一樣?只是個猜想,我對node只知其一;不知其二,真相也不得而知。

  不過至少也能夠得出一個結論,自定義事件並不是雞肋,站在設計模式或者是設計一個框架的角度來看,它的特性或許真是處理某類問題的靈丹妙藥。

相關文章
相關標籤/搜索