一燎含、一個錯誤引發(fā)的思考
在 Weex 子組件中通過 this.$parent.$emit('event')
觸發(fā)父組件的事件万俗,父組件通過 this.$on('event', handler)
接收事件饱溢,從而實現(xiàn)父子組件的通信蝶俱。這在 Native 端表現(xiàn)正常瘦馍,然而當使用 Vue-loader
編譯代碼碳褒,引入 vue-runtime
和 weex-vue-render
在瀏覽器端運行的時候,事件無法正常捕獲莲组,這是什么原因呢诊胞?
假設把前文所說的父組件命名為 father, 子組件命名為 child,起初, Weex 中:
child.$parent === father // true
我們?yōu)榱送ㄖ?father 去做某件事情锹杈,可以在 child 中使用 this.$parent.$emit
撵孤,可是當解析到瀏覽器執(zhí)行的時候,Debugger 發(fā)現(xiàn):
child.$parent === father // false
child.$parent.$parent === father // false
也就是在 father 和 child 之間竭望,多了一層組件的封裝邪码,之前的父子關系發(fā)生了改變,事件自然無法正常傳達
這是因為咬清,在 Weex 中有很多內建組件闭专,底層基于 Native 端實現(xiàn),當通過 vue-runtime
在瀏覽器運行的時候旧烧,需要將這些內建組件用基于瀏覽器的 Vue 組件代替影钉,而這些 Vue 組件要實現(xiàn)類似底層 Native 組件的效果,極有可能需要封裝多層粪滤,也就是會出現(xiàn)上述的父子關系變更的情況
可以認為是 Weex 做得不好的地方,但是我覺著雀扶,就算沒有這個錯誤杖小,也應該避免使用
this.$parent
二、this.$parent 背離了組件解耦的原則
上述的組件通信方式愚墓,是從哪來的奇淫巧技予权,我都已忘記,目前在 Vue 官網上找不到這種使用方法浪册,也就是連官方都不推薦了更印證了不應該使用 this.$parent
的說法扫腺。
其實原因也很簡單,子組件引用父組件的實例村象,這種強關聯(lián)背離了組件的解耦原則笆环,子組件依賴于某一特定的父組件攒至,那么這個子組件只適用在這個父組件下,把這個子組件放到別處躁劣,就無法正常運行(或者有功能的缺失)迫吐,并且一旦出現(xiàn)章節(jié)一中父子關系變更的情況,結果更加難以預料
那么子父組件確實是需要通信的時候账忘,不使用 this.$parent
有什么替代方案么志膀?答案是有的,Vue 中有個 bus 總線鳖擒,子組件通過 bus.$emit
把事件發(fā)到總線中溉浙,任何組件都可以監(jiān)聽這個事件。也就是子組件只負責觸發(fā)事件蒋荚,并不需要關心具體的處理組件戳稽。總線接收到事件信號后圆裕,發(fā)送到監(jiān)聽了該事件的組件處理
對于父到子的通信广鳍,父組件通過 props 向子組件傳入參數,對于這個方向的數據流吓妆,我們卻不用太擔心的解耦的問題赊时,因為父組件作為調用方只需要傳遞子組件需要的參數即可,子組件只需要關心參數行拢,并不需要關心是誰在調用祖秒,同樣可以順利移植,完成解耦
從這個層面來說舟奠,從某種意義上說竭缝,單向數據流促進了組件間的解耦
三、這同樣可以解釋為什么我們需要 Vuex
以這個角度來觀察 Vuex 以及所有單向數據流狀態(tài)控制框架沼瘫,是不是某種意義上的事件總線呢抬纸?
其實 Vuex 不過是 Bus 更高級細致的實現(xiàn)而已,連官方文檔也說了耿戚,有必要好好思考下你是否真的需要 Vuex湿故,如果你的應用本身不復雜,其實只需要一個簡單的 Bus 就夠了