javascript和jquey的自定義事件小結

  • 「經過事件機制,能夠將類設計爲獨立的模塊,經過事件對外通訊,提升了程序的開發效率。」 
  • 能夠把多個關聯但邏輯複雜的操做利用自定義事件的機制靈活地控制好

對象之間經過直接方法調用來交互javascript

1)對象A直接調用對象B的某個方法,實現交互;直接方法調用本質上也是屬於一種特殊的發送與接受消息,它把發送消息和接收消息合併爲一個動做完成;html

方法調用方和被調用方被緊密耦合在一塊兒;由於發送消息和接收消息是在一個動做內完成,因此沒法作到消息的異步發送和接收;java

2)對象A生成消息->將消息通知給一個事件消息處理器(Observable)->消息處理器經過同步或異步的方式將消息傳遞給接收者;node

這種方式是經過將消息發送和消息接收拆分爲兩個過程,經過一箇中間者來控制消息是同步仍是異步發送;web

在消息通訊的靈活性方面比較有優點,可是也帶來了必定的複雜度。可是複雜度通常能夠由框架封裝,消息的發送方和接收方仍然能夠作到比較簡單;瀏覽器

總的來講就是一種鬆耦合的處理,2個對象之間有太多緊密的直接關聯,應該要考慮經過消息通訊解耦,從而提升應用程序的可維護性和重用性app

在JS中,消息的通知是經過事件表達的,當代碼庫增加到必定的規模,就須要考慮將行爲和自定義事件進行解耦。框架

瞭解自定義事件的概念異步

  • 相似DOM的行爲:在DOM節點(包括document對象)監聽並觸發自定義事件。這些事件既能夠冒泡,也能夠被攔截。這正是Prototype、jQuery和MooTools所作的。若是事件不能擴散,就必須在觸發事件的對象上進行監聽。
  • 命名空間:一些框架須要你爲你的事件指定命名空間,一般使用一個點號前綴來把你的事件和原生事件區分開。
  • 自定義額外數據:JavaScript框架容許你在觸發自定義事件時,向事件處理器傳送額外的數據。jQuery能夠向事件處理器傳遞任意數量的額外參數。
  • 通用事件API:只用Dojo保留了操做原生DOM事件的正常API。而操做自定義事件須要特殊的發佈/訂閱API。這也意味着Dojo中的自定義事件不具備DOM事件的一些行爲(好比冒泡)。 
  • 聲明:咱們每每須要在預約義的事件中加入一些特殊的變化(例如,須要Alt鍵按下才能觸發的單擊事件),MooTools運行你定義此類自定義事件。此類事件須要預先聲明,即使你只是聲明他們的名字。任何未聲明的自定義事件不會被觸發。

1、jQuery自定義事件ide

jQuery的自定義事件是經過onone綁定的,而後再經過trigger來觸發這個事件

若有三種狀況須要分別處理:

  1. 用戶提交空值
  2. 用戶提交的用戶名不存在
  3. 用戶提交的用戶名存在

jQuery 提供的自定義事件能夠引入語義,很好地解決問題

//1. 定義自定義事件
$('#username').on('blank.username', function() {
  console.log('請不要留空');
});
$('#username').on('notExist.username', function() {
  console.log('用戶名不存在');
});
$('#username').on('success.username', function() {
  console.log('用戶名存在');
});

//2. 觸發自定義事件
$('.js-submit').on('click', function() {
  var username = $('#username').val();
  username = $.trim(username);
  if (username === '') {
    $('#username').trigger('blank.username');      // 若是 username 爲空值,則觸發 blank.username 事件
  }
  $.post(url, {username: username}, function(data) {
    var res = data;
    if (res.retcode === -1) {
      $('#username').trigger('notExist.username'); // 若是用戶不存在,則觸發 notExist.username 事件
    } else if (res.retcode === 0) {
      $('#username').trigger('success.username'); // 若是用戶存在,則觸發 sucess.username 事件
    }
  });
});

trigger須要處理的問題

1.模擬事件對象,用戶模擬處理中止事件冒泡

triger()方法觸發事件後,會執行瀏覽器默認操做。例如:

$("input").trigger("focus");

以上代碼不只會觸發爲input元素綁定的focus事件,也會使input元素自己獲得焦點(瀏覽器默認操做)。

若是隻想觸發綁定的focus事件,而不想執行瀏覽器默認操做,可使用jQuery中另外一個相似的非冒泡式方法-triggerHandler()方法。

$container.one("focus",function(){
.....
});
$("input").triggerHandler("focus");

該方法會觸發input元素上綁定的特定事件,同時取消瀏覽器對此事件的默認操做,即文本框指觸發綁定的focus事件,不會獲得焦點。

請注意這裏使用了jQuery 的one 來代替on。這二者的區別在於,one 在觸發處理器以後會自動將其刪除。

2.區分事件類型,觸發標準的瀏覽器事件 和 自定義事件名綁定的處理程序。

解決方法:事件名稱+命名空間

p4.on('click.aaa.ccc',function(e,vv,c){
       console.log('p4')
   })
p4.trigger('click.aaa')

2、javascript的自定義事件

1. 簡單的自定義事件

自定義事件到激發這個事件,須要document.createEvent(),event.initEvent(),element.dispatchEvent()這三部,分別是建立事件對象,初始化事件對象,觸發事件

<div id="testBox"></div>
// 1. 建立事件
var evt = document.createEvent('HTMLEvents');
// 2. 定義事件類型,事件初始化
evt.initEvent('customEvent', true, true);
// 3. 在元素上監聽事件,綁定監聽
var obj = document.getElementById('testBox');
obj.addEventListener('customEvent', function(){
    console.log('customEvent 事件觸發了'+event.type);
}, false);
  • console 中輸入 obj.dispatchEvent(evt),能夠看到 console 中輸出「customEvent 事件觸發了」,表示自定義事件成功觸發
  • 遺憾的是在 IE8 及如下版本的 IE 中並不支持document.createEvent()的方法,IE支持的 document.createEventObject()和event.fireEvent()方法,可是通過測試,fireEvent並不能用於自定義事件,傳給它的參數只能是在IE已經定義了的事件,fireEvent 只支持標準事件的觸發。
function foo1(){
        addLog("foo1 is excute");
}
function foo2(){
        addLog("the id is "+idChange.getId()+" now!");
}
if(document.createEvent){ //This is for the stand browser.
        var ev=document.createEvent('HTMLEvents');
        ev.initEvent('fakeEvent',false,false);
        document.addEventListener("fakeEvent",foo1,false);
        document.addEventListener("fakeEvent",foo2,false);
    }else if(document.attachEvent){     //This is for the damn IE
        document.documentElement.fakeEvents = 0; // an expando property
        document.documentElement.attachEvent("onpropertychange", function(event) {
            if (event.propertyName == "fakeEvents") {
                foo1();
            }
        });
        document.documentElement.attachEvent("onpropertychange",function(event){
            if(event.propertyName == "fakeEvents"){
                foo2();
            }
        });
}
function addLog(log){
        var logDiv=document.getElementById('log');
        var p=document.createElement("p");
        p.appendChild(document.createTextNode(log));
        logDiv.appendChild(p);
}
var idChange=function(){
        var id=1;
        return {getId:function(){return id;},
                setId:function(a){
               id=a;
               if(document.dispatchEvent) document.dispatchEvent(ev);
           else if(document.attachEvent)     document.documentElement.fakeEvents++; //This for IE
                    }}
}();

2. 一個完整的事件機制

這個機制支持標準事件和自定義事件的監聽,移除監聽和模擬觸發操做。須要注意的是,爲了使到代碼的邏輯更加清晰,這裏約定自定義事件帶有 'custom' 的前綴(例如:customTest,customAlert),demo

/**
 * @description 包含事件監聽、移除和模擬事件觸發的事件機制,支持鏈式調用
 * @author Kayo Lee(kayosite.com)
 * @create 2014-07-24
 *
 */
 
(function( window, undefined ){
    var Ev = window.Ev = window.$ = function(element){
        return new Ev.fn.init(element);
    };
 
    // Ev 對象構建
    Ev.fn = Ev.prototype = {
        init: function(element){
            this.element = (element && element.nodeType == 1)? element:     document;
    },
 
    /**
     * 添加事件監聽
     * 
     * @param {String} type 監聽的事件類型
     * @param {Function} callback 回調函數
     */
    add: function(type, callback){
        var _that = this;
        if(_that.element.addEventListener){  
            /**
             * @supported For Modern Browers and IE9+
             */
            _that.element.addEventListener(type, callback, false);
        } else if(_that.element.attachEvent){ 
            /**
             * @supported For IE5+
             */
            // 自定義事件處理
            if( type.indexOf('custom') != -1 ){
                if( isNaN( _that.element[type] ) ){
                    _that.element[type] = 0;
                } 
                var fnEv = function(event){
                    event = event ? event : window.event          
                    if( event.propertyName == type ){
                        callback.call(_that.element);
                    }
                };
                _that.element.attachEvent('onpropertychange', fnEv);
 
                // 在元素上存儲綁定的 propertychange 的回調,方便移除事件綁定
                if( !_that.element['callback' + callback] ){
                    _that.element['callback' + callback] = fnEv;
                }
       
            // 標準事件處理
            } else {
                _that.element.attachEvent('on' + type, callback);
            }      
        } else {         
            /**
             * @supported For Others
             */      
            _that.element['on' + type] = callback;
        }
        return _that;
    },
 
    /**
     * 移除事件監聽
     * 
     * @param {String} type 監聽的事件類型
     * @param {Function} callback 回調函數
     */
    remove: function(type, callback){
        var _that = this;     
        if(_that.element.removeEventListener){          
            /**
             * @supported For Modern Browers and IE9+
             */    
            _that.element.removeEventListener(type, callback, false);        
        } else if(_that.element.detachEvent){
             
            /**
             * @supported For IE5+
             */
            // 自定義事件處理
            if( type.indexOf('custom') != -1 ){
                // 移除對相應的自定義屬性的監聽
                _that.element.detachEvent('onpropertychange', _that.element['callback' + callback]);
                // 刪除儲存在 DOM 上的自定義事件的回調
                _that.element['callback' + callback] = null;    
            // 標準事件的處理
            } else {
                _that.element.detachEvent('on' + type, callback);
            }
        } else {        
            /**
             * @supported For Others
             */       
            _that.element['on' + type] = null;  
        }
        return _that;
    },
     
    /**
     * 模擬觸發事件
     * @param {String} type 模擬觸發事件的事件類型
     * @return {Object} 返回當前的 Kjs 對象
     */
    trigger: function(type){
        var _that = this; 
        try {
                // 現代瀏覽器
            if(_that.element.dispatchEvent){
                // 建立事件
                var evt = document.createEvent('Event');
                // 定義事件的類型
                evt.initEvent(type, true, true);
                // 觸發事件
                _that.element.dispatchEvent(evt);
            // IE
            } else if(_that.element.fireEvent){          
                if( type.indexOf('custom') != -1 ){
                    _that.element[type]++;
                } else {
                    _that.element.fireEvent('on' + type);
                }
            }
        } catch(e){
        };
        return _that;     
    }
}
 
Ev.fn.init.prototype = Ev.fn;
 
})( window );
View Code

 參考:

  • http://www.cnblogs.com/aaronjs/p/3452279.html
  • http://kayosite.com/javascript-custom-event.html
  • http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/
相關文章
相關標籤/搜索