談談JS的觀察者模式(自定義事件)

觀察者模式:
這是一種創建鬆散耦合代碼的技術。它定義對象間 一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都將得到通知。由主體和觀察者組成,主體負責發佈事件,同時觀察者通過訂閱這些事件來觀察該主體。主體並不知道觀察者的任何事情,觀察者知道主體並能註冊事件的回調函數。

例子:

假如我們正在開發一個商城網站,網站裏有header頭部、nav導航、消息列表、購物車等模塊。這幾個模塊的渲染有一個共同的前提條件,就是必須先用ajax異步請求獲取用戶的登錄信息。這是很正常的,比如用戶的名字和頭像要顯示在header模塊裏,而這兩個字段都來自用戶登錄後返回的信息。這個時候,我們就可以把這幾個模塊的渲染事件都放到一個數組裏面,然後待登錄成功之後再遍歷這個數組並且調用每一個方法。

function EventTarget(){     
    this.handlers = {}; 
} 
EventTarget.prototype = {     
    constructor: EventTarget,
    addHandler: function(type, handler){
         if (typeof this.handlers[type] == "undefined"){
              this.handlers[type] = [];
         }
         this.handlers[type].push(handler);
     }, 
    fire: function(event){
         if (!event.target){
             event.target = this;
         }
         if (this.handlers[event.type] instanceof Array){
             var handlers = this.handlers[event.type];
             for (var i=0, len=handlers.length; i < len; i++){
                 handlers[i](event); 
            }
         }
     },
     removeHandler: function(type, handler){ 
        if (this.handlers[type] instanceof Array){ 
            var handlers = this.handlers[type]; 
            for (var i=0, len=handlers.length; i < len; i++){ 
                if (handlers[i] === handler){ 
                    break;
                 }
             }
             handlers.splice(i, 1); 
          }
      }
};

大概意思就是,創建一個事件管理器。handles是一個存儲事件處理函數的對象。

addHandle:是添加事件的方法,該方法接收兩個參數,一個是要添加的事件的類型,一個是這個事件的回調函數名。調用的時候會首先遍歷handles這個對象,看看這個類型的方法是否已經存在,如果已經存在則添加到該數組,如果不存在則先創建一個數組然後添加。

fire方法:是執行handles這個對象裏面的某個類型的每一個方法。

removeHandle:是相應的刪除函數的方法。

var Event = {
    // 通過on接口監聽事件eventName
    // 如果事件eventName被觸發,則執行callback回調函數
    on: function (eventName, callback) {
        //我的代碼
        if(!this.handles){
             this.handles={};    
        }      
       if(!this.handles[eventName]){
            this.handles[eventName]=[];
       }
       this.handles[eventName].push(callback);
    },
    // 觸發事件 eventName
    emit: function (eventName) {
        //你的代碼
       if(this.handles[arguments[0]]){
           for(var i=0;i<this.handles[arguments[0]].length;i++){
               this.handles[arguments[0]][i](arguments[1]);
           }
       }
    }
};
var person1 = {};
var person2 = {};
Object.assign(person1, Event);
Object.assign(person2, Event);
person1.on('call1', function () {
    console.log('person1');
});
person2.on('call2', function () {
    console.log('person2');
});
person1.emit('call1'); // 輸出 'person1'
person1.emit('call2'); // 沒有輸出
person2.emit('call1'); // 沒有輸出
person2.emit('call2'); // 輸出 'person2'

完整版

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src='./mapbox-gl.js'></script>
<link href='./mapbox-gl.css' rel='stylesheet' />

<style>

.pageCover
            {
                width:100%;
                height:100%;
                position:absolute;
                z-index:10;
                background-color:#666;
                opacity:0.5;
                display:block;
            }
</style>

</head>
<body>
    <button id="button1">butn1</button>
    <button id="button2">butn2</button>

    <div class="pageCover"></div>
</body>
</html>

<script>


    var Event = {
    _listeners: {},    
    addEvent: function(type, fn) {
        if (typeof this._listeners[type] === "undefined") {
            this._listeners[type] = [];
        }
        if (typeof fn === "function") {
            this._listeners[type].push(fn);
        }    
        return this;
    },
    fireEvent: function(type) {
        var arrayEvent = this._listeners[type];
        if (arrayEvent instanceof Array) {
            for (var i=0, length=arrayEvent.length; i<length; i+=1) {
                if (typeof arrayEvent[i] === "function") {
                    arrayEvent[i]({type: type});    
                }
            }
        }    
        return this;
    },
    removeEvent: function(type, fn) {
        if (typeof type === "string" && arrayEvent instanceof Array) {
            if (typeof fn === "function") {
                for (var i=0, length=this._listeners[type].length; i<length; i+=1){
                    if (this._listeners[type][i] === fn){
                        this._listeners[type].splice(i, 1);
                        break;
                    }
                }
            } else {
                delete this._listeners[type];
            }
        }
        return this;
    }
};



    //test 

//  // 添加自定義事件

Event.addEvent("alert", fnAlert1 = function() {
    alert("第一個彈出!");
}).addEvent("alert", fnAlert2 = function() {
    alert("第二個彈出!");
});

// // 按鈕綁定事件,用來清除自定義事件
var elButton1 = document.getElementById("button1"),
    elButton2 = document.getElementById("button2");

elButton1.onclick = function() {
    Event.removeEvent("alert");
    alert("alert事件清除成功!");

    // 此時後一個按鈕臥底了,故隱藏
    elButton2.style.display = "none";
};

elButton2.onclick = function() {
    Event.removeEvent("alert", fnAlert1);
    alert("第一個alert清除成功!");
};



// 點擊文檔,觸發自定義事件
document.onclick = function(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;

    // 如果文檔點擊元素標籤名不是input
    if (!target || !/input|pre/i.test(target.tagName)) {
        Event.fireEvent("alert");
    }
};

</script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章