源碼分析Vue.js的監(jiān)聽實現(xiàn)教程
前言
相信一說到監(jiān)聽,當然就離不了設計模式中鼎鼎大名的觀察者模式。舉個例子,你家后院著火了,可一定要等到煙霧很大火光很亮你才能發(fā)現(xiàn)啊,可是當你安裝了一個火災預警器,當發(fā)生火災就立馬能夠通知到你了。這就是一個典型的觀察者模式。當然也還有一些其他變種,比如發(fā)布/訂閱(publish/subscribe)模式。
我們知道如果要將數(shù)據(jù)和視圖關聯(lián)起來,在數(shù)據(jù)變更的時候,同步視圖,同理視圖變更,數(shù)據(jù)也發(fā)生變化。vue.js是怎么實現(xiàn)這個的呢?下面我們來揭開它的神秘面紗。
demo:
<script src="../vue.js"> </script>
<div id="app">
<p>
{{ message }}
</p>
<input v-model="message">
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
});
</script>
set: function reactiveSetter(newVal) {
var value = getter ? getter.call(obj) : val;
if (newVal === value) {
return;
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = observe(newVal);
dep.notify();
}
這段代碼出現(xiàn)在解析data屬性的時候,即調用Object.defineProperty方法配置data的屬性。一旦屬性發(fā)生變化,就notify發(fā)送廣播。
Dep.prototype.notify = function () {
// stablize the subscriber list first
var subs = toArray(this.subs);
for (var i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
};
notify 最終是周知subscribe(訂閱者)更新,那么上面的數(shù)據(jù)變更就是發(fā)布者。 subscribe是Watcher這個類的實例化對象,在實例化的時候,會傳入回調函數(shù)來執(zhí)行update,vue弄了一個隊列來執(zhí)行watcher的更新函數(shù),具體可參考源碼。
Watcher.prototype.run = function () {
……
if (value !== this.value || (isObject(value) || this.deep) && !this.shallow) {
……
} else {
this.cb.call(this.vm, value, oldValue);
}
}
this.queued = this.shallow = false;
}
};
在Directive(指令)class中實例化了Watcher,_update函數(shù)負責來更新
var watcher = this._watcher = new Watcher(this.vm, this.expression, this._update, // callback
{
filters: this.filters,
twoWay: this.twoWay,
deep: this.deep,
preProcess: preProcess,
postProcess: postProcess,
scope: this._scope
});
在解析模板的時候會解析Directive,然后綁定,實例化watcher,這樣模板-data就關聯(lián)在一起了。
圖片描述

觀察者模式
林林總總的mvc或者mvvm框架基本也都是利用了觀察者模式,這個也非常有用,尤其在復雜的系統(tǒng)之中。
利用觀察者模式,在典型的ajax應用中,回調的處理邏輯可以不跟請求耦合在一塊,這樣邏輯上也會更加清晰。如下是一個簡單的發(fā)布/訂閱模式的實現(xiàn)
var PubSub = {};
(function (q) {
var topics = {}, subUid = -1;
q.publish = function (topic) {
if(!topics[topic]){
return false;
}
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while(len--){
var args = Array.prototype.slice.call(arguments, 1);
args.unshift(topic);
subscribers[len].callback.apply(this, args);
}
return this;
};
q.subscribe = function (topic, callback) {
if(!topics[topic]){
topics[topic] = [];
}
var subuid = (++subUid).toString();
topics[topic].push({
token: subuid,
callback: callback
});
return subuid;
};
q.unsubscribe = function (subid) {
for(var k in topics){
if(topics[k]){
for(var i = 0, j = topics[k].length; i < j; i++){
if(topics[k][i].token === subid){
topics[k].splice(i, 1);
return subid;
}
}
}
}
return this;
};
})(PubSub);
這就是一個簡單的訂閱發(fā)布系統(tǒng),每注冊一個訂閱者,其實就是將其回調處理的callback保存在一個字典對象的數(shù)組中,字典對象的key值可以隨意定義,只要與發(fā)布時的key對應起來就好。
怎么使用呢?
<script>
var messageLogger = function(){
console.log(JSON.stringify(arguments));
};
var subscription = PubSub.subscribe('/newMessage', messageLogger);
// {"0":"/newMessage","1":"hello world"}
PubSub.publish('/newMessage', 'hello world');
// {"0":"/newMessage","1":["test","a","b","c"]}
PubSub.publish('/newMessage', ['test', 'a', 'b', 'c']);
// {"0":"/newMessage","1":{"sender":"hello world","body":"hey man"}}
PubSub.publish('/newMessage', {
sender: 'hello world',
body: 'hey man'
});
PubSub.unsubscribe(subscription);
PubSub.publish('/newMessage', ['test', 'a', 'b', 'c'], 1);
</script>
最后一個將不會打印出來,因為已經(jīng)取消訂閱了。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
- 用Vue.js實現(xiàn)監(jiān)聽屬性的變化
- Vue.JS入門教程之事件監(jiān)聽
- 詳解使用vue-router進行頁面切換時滾動條位置與滾動監(jiān)聽事件
- vue.js 1.x與2.0中js實時監(jiān)聽input值的變化
- 詳解Vue監(jiān)聽數(shù)據(jù)變化原理
- vue監(jiān)聽滾動事件實現(xiàn)滾動監(jiān)聽
- Vue.js實戰(zhàn)之通過監(jiān)聽滾動事件實現(xiàn)動態(tài)錨點
- Vue監(jiān)聽數(shù)組變化源碼解析
- vuejs2.0實現(xiàn)分頁組件使用$emit進行事件監(jiān)聽數(shù)據(jù)傳遞的方法
- Vue監(jiān)聽數(shù)據(jù)對象變化源碼
相關文章
在vue中使用Echarts利用watch做動態(tài)數(shù)據(jù)渲染操作
這篇文章主要介紹了在vue中使用Echarts利用watch做動態(tài)數(shù)據(jù)渲染操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
Vue項目中使用addRoutes出現(xiàn)問題的解決方法
大家應該都知道可以通過vue-router官方提供的一個api-->addRoutes可以實現(xiàn)路由添加的功能,事實上就也就實現(xiàn)了用戶權限,這篇文章主要給大家介紹了關于Vue項目中使用addRoutes出現(xiàn)問題的解決方法,需要的朋友可以參考下2021-08-08

