一、一個錯誤引發的思考
在 Weex 子元件中通過 this.$parent.$emit(`event`)
觸發父元件的事件,父元件通過 this.$on(`event`, handler)
接收事件,從而實現父子元件的通訊。這在 Native 端表現正常,然而當使用 Vue-loader
編譯程式碼,引入 vue-runtime
和 weex-vue-render
在瀏覽器端執行的時候,事件無法正常捕獲,這是什麼原因呢?
假設把前文所說的父元件命名為 father, 子元件命名為 child,起初, Weex 中:
child.$parent === father // true複製程式碼
我們為了通知 father 去做某件事情,可以在 child 中使用 this.$parent.$emit
,可是當解析到瀏覽器執行的時候,Debugger 發現:
child.$parent === father // false
child.$parent.$parent === father // false複製程式碼
也就是在 father 和 child 之間,多了一層元件的封裝,之前的父子關係發生了改變,事件自然無法正常傳達
這是因為,在 Weex 中有很多內建元件,底層基於 Native 端實現,當通過 vue-runtime
在瀏覽器執行的時候,需要將這些內建元件用基於瀏覽器的 Vue 元件代替,而這些 Vue 元件要實現類似底層 Native 元件的效果,極有可能需要封裝多層,也就是會出現上述的父子關係變更的情況
可以認為是 Weex 做得不好的地方,但是我覺著,就算沒有這個錯誤,也應該避免使用
this.$parent
二、this.$parent 背離了元件解耦的原則
上述的元件通訊方式,是從哪來的奇淫巧技,我都已忘記,目前在 Vue 官網上找不到這種使用方法,也就是連官方都不推薦了更印證了不應該使用 this.$parent
的說法。
其實原因也很簡單,子元件引用父元件的例項,這種強關聯背離了元件的解耦原則,子元件依賴於某一特定的父元件,那麼這個子元件只適用在這個父元件下,把這個子元件放到別處,就無法正常執行(或者有功能的缺失),並且一旦出現章節一中父子關係變更的情況,結果更加難以預料
那麼子父元件確實是需要通訊的時候,不使用 this.$parent
有什麼替代方案麼?答案是有的,Vue 中有個 bus 匯流排,子元件通過 bus.$emit
把事件發到匯流排中,任何元件都可以監聽這個事件。也就是子元件只負責觸發事件,並不需要關心具體的處理元件。匯流排接收到事件訊號後,傳送到監聽了該事件的元件處理
對於父到子的通訊,父元件通過 props 向子元件傳入引數,對於這個方向的資料流,我們卻不用太擔心的解耦的問題,因為父元件作為呼叫方只需要傳遞子元件需要的引數即可,子元件只需要關心引數,並不需要關心是誰在呼叫,同樣可以順利移植,完成解耦
從這個層面來說,從某種意義上說,單向資料流促進了元件間的解耦
三、這同樣可以解釋為什麼我們需要 Vuex
以這個角度來觀察 Vuex 以及所有單向資料流狀態控制框架,是不是某種意義上的事件匯流排呢?
其實 Vuex 不過是 Bus 更高階細緻的實現而已,連官方文件也說了,有必要好好思考下你是否真的需要 Vuex,如果你的應用本身不復雜,其實只需要一個簡單的 Bus 就夠了