★2019 前端進階之路★Vue 組件間通信實戰干貨!

初體驗

Vue.js 在現今使用有多廣泛不用多說,而 Vue 的一大特點就是組件化。本期要講的,便是 Vue 組件間通信方式的總結,這也幾乎是近年 Vue 面試中的必考題。注:文中示例都基于 Vue 腳手架講解,會用到一些?Element UI?示例。

【前端進階之路】會作為一個新系列連載,后續會更多優質前端內容,感興趣的同學不妨關注一下。

①組件

組件是可以復用的 Vue 實例。 —?Vue 官方文檔;

在進入主題之前,還是決定先簡單聊聊組件。在 Vue 中,根據注冊方式的不同,可以分為:

?????局部組件 (局部注冊)

?????全局組件 (全局注冊)

顧名思義,全局注冊的組件,可以用在 Vue 實例的任意模板中。但是帶來的隱患是,在 webpack 模塊化構建時,即便你沒有在項目中使用這個組件,依然會打包到最終的項目代碼中。而局部組件,則需要在使用到的實例中注冊該組件。

根據應用場景的不同,又可以分為:

????1.頁面組件:我們使用 Vue 時,每個路由代表的頁面,都可以稱之為組件。

????2.基礎組件:就像上面栗子中的 Icon 組件,就是一個典型的基礎組件?;旧喜粨诫s業務邏輯,在項目中可能被大量使用,易于移植。類似的基礎組件還有 Button、Input 等,常見于各類 UI 組件庫。

????3.業務組件:業務組件和項目具體的業務邏輯有大量耦合,一般抽離于當前項目。

以上就是組件的簡單介紹,那我們到底為什么要推崇組件化?組件化有什么好處?復用?我個人認為組件化最大的好處,便是解耦,易于項目管理。所以在大型項目管理中,組件化是非常有必要的。當然,這并不是今天學習的重點,以后有機會再聊。

正因為在 Vue 中處處都是組件,而我們也偏向于組件化、模塊化。那我們在一堆組件中,便需要解決一個問題 — 組件間通信。下面,我們就進入今天的主題,Vue 的組件間通信。

②組件間通信

組件間通信是我們在 Vue 項目中不可避免的問題,深刻了解了 Vue 組件間通信的幾種方式,才能讓我們在處理各種交互問題時游刃有余。

Props

Vue 中,最基本的通信方式就是 Props,它是父子組件通信中父組件傳值給子組件的一種方式。它允許以數組形式接收,但是更推薦你開啟類型檢查的形式。更詳細的類型檢查前往?vue prop文檔。

我們都知道,Props 是單向數據流,這是 Vue 為了避免子組件意外改變父組件的狀態,從而導致數據流向難以理解而做出的限制。所以 Vue 推薦需要改動的時候,通過改變父組件的值從而觸發 Props 的響應?;蛘?,我們可以在接收非引用類型的值時,使用子組件自身的 data 做一次接收。

為什么是非引用類型呢,因為在 JavaScript 中,引用類型的賦值,實際是內存地址的傳遞。所以上面栗子中的簡單賦值,顯然會指向同一個內存地址,所以如果是數組或是對象,你可能需要一次深拷貝。

上面這個操作有一些缺陷,不能序列化函數、undefined、循環引用等……

事實上,在 Props 是引用類型時,單獨修改對象、數組的某個屬性或下標,Vue 并不會拋出錯誤。當然,前提是你要非常清楚自己在做什么,并寫好注釋,防止你的小伙伴們疑惑。

有的同學可能知道,在組件上綁定的屬性,如果沒有在組件內部用 Props 聲明,會默認綁定到組件的根元素上去。還是之前的栗子:

結果如下:

這是 Vue 默認處理的,而且,除了 class 和 style 采用合并策略,其它特性(如上栗 type)會替換掉原來根元素上的屬性值。當然,我們也可以顯示的在組件內部關閉掉這個特性:

利用 inheritAttrs,我們還可以方便的把組件綁定的其它特性,轉移到我們指定的元素上。這就需要用到下一個我們要講的?$attrs?了。

attrs、listeners

我們在使用組件庫的時候經常會這么寫:

實際渲染后:

可以看到我們指定的的 placeholder 是渲染在 input 上的,但是 input 并不是根元素。難道都用 Props 聲明后,再賦值給 input?這種情況就可以用到?$attrs?了,改造一下我們之前那個栗子。


可以看到,type 已經轉移到了子元素 input 標簽上,但是 class 沒有。這是因為inheritAttrs: false選項不會影響 style 和 class 的綁定。可以看出$attrs則是將沒有被組件內部 Props 聲明的傳值(也叫非 Props 特性)收集起來的一個對象,再通過 v-bind 將其綁定在指定元素上。這也是 Element 等組件庫采用的策略。

這里需要注意一點,通過 $attrs 指定給元素的屬性,不會與該元素原有屬性發生合并或替換,而是以原有屬性為準。舉個例子,假如我將上述 input 的 type 默認設置為 password。

則不會采用 $attrs 中的 type: 'text',將以 password 為準,所以如果需要默認值的屬性,建議不要用這種方式。

$listeners同$attrs類似,可以看做是一個包含了組件上所有事件監聽器(包括自定義事件、不包括.native修飾的事件)的對象。它也支持上述的寫法,適用于將事件安放于組件內指定元素上。

給之前的栗子綁定一個聚焦事件,在子組件中通過$listeners綁定給 input,則會在 input 聚焦時觸發。

那么除了用在這種給組件內指定元素綁定特性和事件的情況,還有哪些場景可以用到呢?官方說明:在創建更高層次的組件時非常有用。比如在祖孫組件中傳遞數據,在孫子組件中觸發事件后要在祖輩中做相應更新。我們繼續之前的栗子:在孫輩組件觸發點擊事件,然后在祖輩中修改相應的 data。

這樣就能很方便的在多級組件的子級組件中,快速訪問到父組件的數據和方法。正如在剛才的例子中,button 點擊時,是直接調用的 communication.vue 中定義的方法。

總結:

1、子組件觸達父組件的方式:Props、$parent、$attrs、$listeners、provide 和 inject、$dispatch

2、父組件觸達子組件的方式:$emit和$on、$children、$ref、broadcast

3、全局通信:EventBus、Vuex

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容