詳解從vue的組件傳值著手觀察者模式
觀察者模式
首先,提到觀察者模式,這不禁讓我想到瞭MVVM,MVVM架構模式感覺用到瞭觀察者的思想。
我們還是按照慣例,瞭解一下什麼是觀察者模式
觀察者模式,類似發佈訂閱模式,完成這個動作首先最少得有兩個不同的對象,或者多個對象,他更像是一種一隊多的依賴關系,也就是一種對象的狀態發生改變,與其相關所有的對象的狀態都會發生改變;比如說朋友圈這個功能,一個人可能有上百個好友,當我發佈一條朋友圈後,所有和我成為好友的人都會看見這個朋友圈,當另一個人點贊後,所有你的好友其他點贊的人也會收到通知,這很像觀察者,也就是我是發佈者,我的好友是訂閱者。
Vue傳值
然後我們看一下什麼是vue,vue的原理大傢都知道,他是一種自底向上的一種深入響應式的雙向綁定模式,即MVVM,也就是說,vue關註model的變化,model的變化讓mvvm框架更新dom,從而產生視圖view變化。
舉一個項目中很常見的例子:
在寫vue項目中我們都用過父子組件傳值,但是兄弟組件傳值是怎麼實現的,首先我們可以用vuex,這很常見,但是還有一種方法不知道你用過沒有,就是Bus,這個Bus隻是一種命名而已,叫什麼無所謂,你可以叫飛機大炮都可以,這不重要,我們主要看看他是怎麼實現的:
第一步,我們先在main.js中註冊一下bus
Vue.prototype.$Bus = new Vue()
我們往vue的原型裡註冊瞭一個全局變量$Bus,他的值是vue的實例,也就是說,到現在為止,$Bus裡邊有瞭vue所有的屬性和方法,這下就好操作瞭
第二步,我們開始發送消息
這就很符合觀察者模式的發佈訂閱模式
我們在組件1中寫如下代碼:
<template> <div> <button @click="send">發送</button> </div> </template> <script> export default { methods: { send () { this.$Bus.$emit("send",'接收的信息') } } } </script>
點擊按鈕發送一條信息,這個按鈕也就是充當發佈者,我們用到瞭vue的$emit這個api,那麼訂閱者是什麼呢?我不說你也應該想到瞭,對,就是他
第三步,在組件三中接收消息
<template> <div> {{message}} </div> </template> <script> export default { data () { return { message: '' } }, mounted () { this.$Bus.$on('send', (msg) => { this.message = msg }) } } </script>
就是用$on這個屬性充當接收者
從上可以看出,vue很多地方用到瞭觀察者的思想,包括他的雙向綁定也是如此
vue的機制
從上圖我們可以看出,vue是通過Object.defineProperty實現對數據的劫持,然後中間做瞭一個中轉,最後渲染到vue層。
我們可以肯定的是,vue.js借鑒瞭觀察者模式,但是我感覺還是有點區別的,觀察者模式跟註重的是事件驅動,比如我買房這個動作,第一次和銷售瞭解可能沒有合適的房源,然後銷售就會跟你說: ‘如果有合適的房源我們會第一時間通知你’,當有新房源的時候他會給你打電話通知你,這一系列的根源是買房這個事件,他驅動瞭整套流程。而vue我們都知道是數據驅動,也就是隻有data裡的值發生改變的話,Object.defineProperty才會對他劫持,從而去更新dom,觸發視圖的更新。
那麼有沒有更符合觀察者模式特征的?
當然是node.js的events事件瞭。
首先我們看看events的工作流程:
var events = require('events'); // 創建 eventEmitter 對象 var eventEmitter = new events.EventEmitter(); // 創建事件處理程序 var connectHandler = function connected() { console.log('連接成功。'); // 觸發 data_received 事件 eventEmitter.emit('data_received'); } // 綁定 connection 事件處理程序 eventEmitter.on('connection', connectHandler); // 使用匿名函數綁定 data_received 事件 eventEmitter.on('data_received', function(){ console.log('數據接收成功。'); }); // 觸發 connection 事件 eventEmitter.emit('connection'); console.log("程序執行完畢。");
輸出一下:
這就完全符合觀察者的工作模式,由emit發佈,由on接收。所以說,node.js提供瞭很好的監聽機制,還有他對整個事務的處理 。其支持瞭nodejs最特色的I/O模式,比如我們啟動http服務時會監聽其 connect / close,http.request時會監聽 data / end等。
還有沒有類似的案例呢?
當然,js有一個事件監聽者—-addEventListener,也有點觀察者的意思,具體用法我就不說瞭,想必大傢用的都很熟悉。
其實隻要你認真想一想,還是有很多地方有觀察者的身影的,最簡單的就是一個點擊事件,是不是也有其意思,發佈者是一個按鈕,而接收者可以是表單,彈層等任何東西。
觀察者模式存在的意義
首先我們說說他的優點:
1,觀察者模式需要在觀察者和被觀察者之間建立一個耦合,他需要一個更加抽象化將二者聯系在一起
2,觀察者模式支持廣播,也就是一對多的關系,這就讓我們很容易想到一個技術,就是socket,具體可以參考vue項目使用websocket技術
然鵝,他也是優缺點的:
1,創建訂閱者本身要消耗一定的時間和內存
2,當訂閱一個消息時,也許此消息並沒有發生,但這個訂閱者會始終存在內存中。
3,觀察者模式弱化瞭對象之間的聯系,這本是好事情,但如果過度使用,對象與對象之間的聯系也會被隱藏的很深,會導致項目的難以跟蹤維護和理解。
等會兒,還有一個模式叫發佈訂閱模式,很多人都以為他就是觀察者模式(包括我),後來我上網查瞭一下,發現他們還是有區別的,我們可以說觀察者模式和發佈訂閱模式很像,真的很像,但是本質還是有點區別的,最根本的就是調度中心不同。
舉個例子,觀察者模式更註重是目標和觀察者是抽象類,比如天氣預報,觀察者A負責監聽天氣的變化,而B想得知天氣的變化需要將自己註冊到A中,而天氣變化的時候A觸發天氣變化,調度B的接口更新變化。
而發佈訂閱模式是如何完成這個動作的呢?A想要感知天氣變化,需要B這個調度中心,而B得到天氣變化需要依賴C的觸發,可能我解釋的不是很清楚,網上有兩個圖比較好
以上就是詳解從vue的組件傳值著手觀察者模式的詳細內容,更多關於從vue的組件傳值著手觀察者模式的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Node.js原理阻塞和EventEmitter及其繼承的運用實戰
- 使用Vue.js實現數據的雙向綁定
- Node.js的非阻塞I/O、異步與事件驅動介紹
- 詳細聊聊Vue.js中的MVVM
- 淺談JS和Nodejs中的事件驅動