Vue組件通訊的幾種方式

父組件經過 Prop 向子組件傳遞數據

這個數據流是單向的。數據流向是從父組件傳到子組件。也就是說,父級 prop 的更新會向下流動到子組件中,可是反過來則不行。
如今咱們須要寫一個博文組件,展現博文的標題和內容。標題和內容這些數據是從父組件得到的。
第一步,定義一個組件,這裏用註冊全局組件的方式,子組件用prop接收來自父組件的數據:html

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h2>{{ post.title }}</h2>
      <div v-html="post.content"></div>
    </div>
  `
});

第二步,初始化一個Vue實例並掛載到對應的HTML結構:vue

// html
<div id="app">
  <blog-post :post="post" v-for="(post, index) in postArr" :key="index"></blog-post>
</div>

// js
new Vue({
  el: "#app",
  data: {
    postArr: [
      {
          title: 'My name is Judy',
        content: 'something here '
      },
      {
          title: 'My job is coding',
        content: 'something here '
       },
       {
            title: 'I like coding',
          content: 'something here '
       }
    ]
  }
});

demo:父組件經過 Prop 向子組件傳遞數據vuex

子組件經過事件向父級組件發送消息

在咱們開發 <blog-post> 組件時,它的一些功能可能要求咱們和父級組件進行溝通。例如咱們可能會引入一個可訪問性的功能來放大博文的字號,同時讓其餘部分的博文保持默認的字號。
仍是剛纔那個demo,在其父組件中,咱們能夠經過給每一條博文的數據添加一個 postFontSize 數據屬性來控制每篇博文字體的大小。app

// js
new Vue({
  el: "#app",
  data: {
    postArr: [
      {
        postFontSize: 1,
          title: 'My name is Judy',
        content: 'something here '
      },
      {
        postFontSize: 1,
          title: 'My job is coding',
        content: 'something here '
      },
      {
        postFontSize: 1,
        title: 'I like coding',
        content: 'something here '
      }
    ]
  }
});

如今咱們須要給子組件添加一個按鈕。當點擊這個按鈕時,咱們須要告訴父級組件放大全部博文的文本。恰好 Vue 實例提供了一個自定義事件的系統來解決這個問題。咱們能夠調用內建的 $emit 方法並傳入事件的名字,來向父級組件觸發一個事件。改寫一會兒組件:ide

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h2>{{ post.title }}</h2>
      <button @click="$emit('enlarge-text')">
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
});

而後咱們能夠用 v-on 在博文組件上監聽這個事件,就像監聽一個原生 DOM 事件同樣:post

<div id="app">
  <blog-post 
    @enlarge-text="post.postFontSize += 0.1" 
    :post="post" 
    v-for="(post, index) in post_arr" 
    :key="index"
    :style="{ fontSize: post.postFontSize + 'em' }"
  ></blog-post>  
</div>

demo:子組件經過事件向父級組件發送消息字體

以上爲經常使用的父組件向子組件傳遞數據、子組件經過事件向父級組件發送消息的兩種方式。ui

$parent訪問父級組件實例

$parent 屬性能夠用來從一個子組件訪問父組件的實例。它提供了一種機會,能夠在後期隨時觸達父級組件,以替代將數據以 prop 的方式傳入子組件的方式,實際上這不是一種數據傳遞,而是子組件主動發起的數據查找。
可是Vue並不推薦這麼作。在絕大多數狀況下,觸達父級組件會使得咱們的應用更難調試和理解,尤爲是咱們變動了父級組件的數據的時候。當咱們稍後回看那個組件的時候,很難找出那個變動是從哪裏發起的。
在一些可能適當的時候,咱們須要特別地共享一些組件庫,就能夠考慮用$parent。Vue官網稱這些狀況爲【邊界狀況】。
假設有一個Google地圖組件:this

<google-map>
  <google-map-markers v-bind:places="iceCreamShops"></google-map-markers>
</google-map>

這個 <google-map> 組件能夠定義一個 map 屬性,全部的子組件都須要訪問它。在這種狀況下 <google-map-markers> 能夠經過相似 this.$parent.getMap 的方式訪問那個地圖,以便爲其添加一組標記。
點擊這裏查看官方文檔給出的demogoogle

ref 特性訪問子組件實例或子元素

儘管存在 prop 和事件,有的時候仍可能須要在 JavaScript 裏直接訪問一個子組件。爲了達到這個目的,咱們能夠經過 ref 特性爲這個子組件賦予一個 ID 引用。
例如:

<base-input ref="usernameInput"></base-input>

如今在已經定義了這個 ref 的組件裏就可使用:

this.$refs.usernameInput

來訪問這個 <base-input> 實例,以便不時之需。
另外,vm.$children也能夠訪問當前實例的直接子組件。須要注意 $children 並不保證順序,也不是響應式的。

當咱們須要訪問子組件或者子元素,推薦使用 ref 而不是 $children
由於 ref 能幫咱們訪問到的是任意子組件實例或者子元素,$children 只能訪問到直接子組件

Vuex

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。
什麼意思呢?在實際開發中,咱們會遇到有一處或者多處須要被多個實例間共享的狀態,Vuex就是爲咱們提供了這樣一個模式。因此個人理解是Vuex不只僅是適用於父子組件的通訊了,它適用於全部組件共享某些必要的數據狀態。
關於Vuex的使用咱們這裏不詳細展開討論了,貼一個Vuex的文檔地址

一些補充

前面咱們提到google地圖組件,相似這樣的:

<google-map>
  <google-map-region v-bind:shape="cityBoundaries">
    <google-map-markers v-bind:places="iceCreamShops"></google-map-markers>
  </google-map-region>
</google-map>

在這個組件裏,全部 <google-map> 的後代都須要訪問一個 getMap 方法,以便知道要跟那個地圖進行交互。不幸的是,使用 $parent 屬性沒法很好的擴展到更深層級的嵌套組件上,也就是說,只有<google-map-region>能經過 $parent 訪問到它的直接父組件<google-map>的 getMap 方法。這種狀況能夠用依賴注入 provideinject 解決。

provide 選項容許咱們指定咱們想要提供給後代組件的數據/方法。在這個例子中,就是 <google-map> 內部的 getMap 方法:

provide: function () {
  return {
    getMap: this.getMap
  }
}

而後在任何後代組件裏,咱們均可以使用 inject 選項來接收指定的咱們想要添加在這個實例上的屬性:

inject: ['getMap']

點擊這裏查看官方文檔的demo

相比 $parent 來講,這個用法可讓咱們在任意後代組件中訪問 getMap,而不須要暴露整個 <google-map> 實例。這容許咱們更好的持續研發該組件,而不須要擔憂咱們可能會改變/移除一些子組件依賴的東西。同時這些組件之間的接口是始終明肯定義的,就和 props 同樣。

實際上,你能夠把依賴注入看做一部分「大範圍有效的 prop」,除了:

  • 祖先組件不須要知道哪些後代組件使用它提供的屬性
  • 後代組件不須要知道被注入的屬性來自哪裏

我看了不少篇總結Vue父子組件通訊方式的博客都沒有提到依賴注入,不過我以爲依賴注入也實現了通訊——由父組件經過 provide 把數據暴露出去,子組件經過 inject 接收數據。

以上就是我閱讀官方文檔總結出來的Vue組件通訊的幾種方式,大部份內容和demo都來源於官網文檔,瞭解更多能夠閱讀文檔:Vue文檔地址。文章所有內容僅表明我的觀點,歡迎批評或者與我討論。感謝你的閱讀。

相關文章
相關標籤/搜索