01、模式的概念
熟悉Vue的小伙伴都知道,在Vue中使用“觀察者模式”去通知視圖更新,使用“發(fā)布訂閱”$on,$emit來(lái)實(shí)現(xiàn)自定義事件,所以搞清楚兩者之間的關(guān)系很重要啦!
02、觀察者模式
一個(gè)對(duì)象(觀察者)訂閱另一個(gè)對(duì)象(主題),當(dāng)主題被激活的時(shí)候,觸發(fā)觀察者里面的事件。
舉個(gè)例子:打點(diǎn)滴時(shí),我們會(huì)觀察吊瓶的變化,當(dāng)快打完時(shí),就要通知護(hù)士來(lái)取針。這里護(hù)士/我們就是觀察者(Obeserver),吊瓶就是被觀察者/主題。
class Subject { //被觀察者數(shù)據(jù)--吊瓶
constructor(name="蛋糕老師"){
this.state = 100;
this.name = name;
this.obs = [] //會(huì)有多個(gè)觀察者
}
addObs(ob){
this.obs.push(ob)
}
setState(state){ //改變狀態(tài)的方法
this.state = state
//要去通知觀察者去做動(dòng)作 -- 拔針
this.obs.forEach((ob)=>{
ob.update(this) //讓觀察者去做更新
})
}
}
class Obeserver{ //觀察者 -- 醫(yī)生
constructor(name){
this.name = name;
//在觀察者里面是否可以記錄/觀察了哪些數(shù)據(jù)
}
update(subject){
//醫(yī)生也有可能觀察多個(gè)打針的人
if (!subject.state) {
console.log(`${this.name} 收到通知 :${subject.name} 的 帶瓶打完啦!`)
}else {
console.log(` ${this.name} 收到通知 :${subject.name} 的帶瓶量: ${subject.state}!`)
}
}
}
var zhiliao = new Subject();
var hushi = new Obeserver("護(hù)士");
var yisheng = new Obeserver("醫(yī)生")
zhiliao.addObs(hushi)
zhiliao.addObs(yisheng)
zhiliao.setState(50)
03、發(fā)布訂閱
訂閱者把自己想要訂閱的事件注冊(cè)到調(diào)度中心,當(dāng)發(fā)布者發(fā)布事件到調(diào)度中心(就是該事件被觸發(fā)),再由調(diào)度中心統(tǒng)一調(diào)度訂閱者注冊(cè)到調(diào)度中心的處理代碼。
其實(shí)簡(jiǎn)單理解就是我們的自定義事件,比如在Vue中,Vue實(shí)例($bus)就是統(tǒng)一的調(diào)用中心,我們使用$bus去$on一個(gè)自定義事件myEvent就是發(fā)布者發(fā)布一個(gè)事件到調(diào)度中心,然后在其他地方$bus.$emit(myEvent)一下就相當(dāng)于事件被觸發(fā),然后$bus就去執(zhí)行對(duì)應(yīng)事件的回調(diào)函數(shù) 。var Event = {
_listeners: {},
// 添加
$on: function(type, fn) {
if (typeof this._listeners[type] === "undefined") {
this._listeners[type] = [];
}
if (typeof fn === "function") {
this._listeners[type].push(fn);
}
return this;
},
// 觸發(fā)
$emit: function(type) {
var arrayEvent = this._listeners[type];
if (arrayEvent instanceof Array) {
for (var i=0, length=arrayEvent.length; i
if (typeof arrayEvent[i] === "function") {
arrayEvent[i]({ type: type });
}
}
}
return this;
},
// 刪除
$off: function(type, fn) {
var arrayEvent = this._listeners[type];
if (typeof type === "string" && arrayEvent instanceof Array) {
if (typeof fn === "function") {
for (var i=0, length=arrayEvent.length;i+=1){
if (arrayEvent[i] === fn){
this._listeners[type].splice(i, 1);
break;
}
}
} else {
delete this._listeners[type];
}
}
return this;
}
};
04、總結(jié)
學(xué)習(xí)這兩種模式,其實(shí)就是為了代碼解耦 ,讓每個(gè)獨(dú)立的對(duì)象分開(kāi)。需要從日常的業(yè)務(wù)場(chǎng)景去觀察,比如在分頁(yè)插件中,就可以利用“發(fā)布訂閱”為點(diǎn)擊每一個(gè)分頁(yè)數(shù)的時(shí)候觸發(fā)($emit)一個(gè)自定義事件,如果需要在點(diǎn)擊分頁(yè)的是做一些其他的時(shí)候,就可以在外面$on 這個(gè)事件,那么分頁(yè)插件就可以很好的封裝起來(lái),不用給里面?zhèn)鬟f參數(shù)或者回調(diào)函數(shù)之類(lèi)的了。