觀察者模式:
這是一種創建鬆散耦合代碼的技術。它定義對象間 一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都將得到通知。由主體和觀察者組成,主體負責發佈事件,同時觀察者通過訂閱這些事件來觀察該主體。主體並不知道觀察者的任何事情,觀察者知道主體並能註冊事件的回調函數。
例子:
假如我們正在開發一個商城網站,網站裏有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>