Vue 父子組件間的通訊

前言 在 Vue 項目中父子組件的通訊是很是常見的,最近作項目的時候發現對這方面的知識還不怎麼熟練,在這邊作一下筆記,系統學習一下吧。html

1 父組件傳值給子組件

1.1 傳值寫法

父組件傳值給子組件,這個就比較常見了,直接用 props 就能夠了。可是就算是 props 子組件那邊也有三種寫法,以下面代碼所示:
父組件vue

<!-- 兩種狀況 -->
<!--靜態傳值-->
<child name="xhm"></child>
<!--動態傳值-->
<child :name="userName"></child>

子組件數組

// 1 簡單粗暴就給個名稱的狀況
props:['name'],
// 2 給個名稱順便指定個類型,若是父組件傳遞過來的值類型不對的話就會報錯
props:{
    name:String
},
// 3 給個名稱不只指定了類型,還順便送了個默認值,當父組件傳個空過來或者啥都沒傳過來的時候就用默認值了
props: {
  name: {
    type: String,
    default: 'xhm',
  }
},

注意一下的話,若是是數組或者是對象要默認值的話,直接設置默認數組或者默認對象會報錯,須要用工廠函數返回,以下:瀏覽器

props: {
  arr:{
    type:Array,
    default:()=>{
       return [1,2,3]
    }
  }
},
// 對象也是和上面一個用工廠函數

1.2 子組件使用父組件的值

因爲單向數據流的限制,咱們不能直接在子組件中修改 props 的值,當咱們修改的時候會報錯,官方的說法是:函數

全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。這樣會防止從子組件意外改變父級組件的狀態,從而致使你的應用的數據流向難以理解。

額外的,每次父級組件發生更新時,子組件中全部的 prop 都將會刷新爲最新的值。這意味着你不該該在一個子組件內部改變 prop。若是你這樣作了,Vue 會在瀏覽器的控制檯中發出警告。學習

因此啊,若是你不僅是想在子組件中簡單的渲染父組件傳過來的值的話,那麼能夠用下面的兩種方法。this

  1. 這個 prop 用來傳遞一個初始值;這個子組件接下來但願將其做爲一個本地的 prop 數據來使用。在這種狀況下,最好定義一個本地的 data 屬性並將這個 prop 用做其初始值:
props: ['name'],
data() {
  return {
    userName:this.name,
  };
},
  1. 這個 prop 以一種原始的值傳入且須要進行轉換。在這種狀況下,最好使用這個 prop 的值來定義一個計算屬性:
props: ['name'],
computed: {
  userName(){
    return this.firstName + this.name
  }
},

2 子組件傳值給父組件

雖然咱們說是要單向數據流,可是不少時候,咱們在子組件改變了某些值以後,仍是要反饋給父組件,讓父組件作一下修改,那麼這個時候就要想着子組件向父組件傳值啦。有下面這麼兩種方式雙向綁定

2.1 emit 方法

這個基本都是用 emit 來傳遞了,用法直接看代碼吧:
子組件code

// props:['name]

// methods 裏
update(){
  this.$emit('update','ljy');
  // 第一個參數:事件名,第二個參數:傳遞給事件方法的參數
}

父組件htm

/* template 裏面的代碼,監聽子組件裏面的 update 事件,調用父組件的 childUpdate 方法

 <child :name="userName" @update="childUpdate"></child>

*/
// methods
chidlUpdate(val){
  // val 參數就是子組件傳遞過來的數據
  this.userName = val;
}

雖然這樣是能夠實現子組件向父組件傳值,可是寫多一個方法感受很煩,因此 vue 官方高出了一個 以 update:myPropName 的模式觸發事件。,這個是啥,舉個例子,咱們的子組件中有一個 name 的 props,咱們用下面這個形式通知父組件

this.$emit('update:name', newName)
// this.$emit('update:props中的變量名', 新的值)

而後父組件能夠監聽那個事件並根據須要更新一個本地的數據屬性:

<child :name="userName" @update:name="userName = $event"></child>

這樣當咱們在子組件觸發那個修改的方法的時候,父組件的 userName 變量就會更新爲 newName了,而後爲了方便起見,官方提供了一個縮寫,即 .sync 修飾符。看代碼吧:

<child :name.sync="userName"></child>

上面的代碼和前面的代碼是一個效果,是否是方便了不少。舒服了吧。

2.2 利用淺拷貝(不推薦)

這個的話是針對於 對象和數組那些引用類型的數據而言的,因爲這些存在淺拷貝的問題(不明白淺拷貝的看這篇文章),因此能夠利用這點來實現子父組件的「同生共死」,看代碼吧

// 假設 name 是一個對象或者數組
props:['name'],
return {
  userName:this.name,
};

就這樣?!

沒錯就是這麼簡單粗暴,因爲淺拷貝的問題,咱們在子組件修改 userName 的時候,從父組件傳遞過來的那個值也會改變的,而後就會實現 props 的「雙向綁定」了。可是通常沒人會這麼幹,由於這樣會形成維護上的問題,會讓人以爲咋沒幹啥父組件的值咋就變了,會讓人頭禿啊,因此除非你項目中非得要搞這麼一個子父組件 props 的「同生共死」,那就這麼幹吧。

3 子組件調用父組件的方法

不知道這樣的叫法對不對,反正就這樣啦。總結以後又下面這幾種方法

3.1 emit

其實原本 emit 就是用於子組件向父組件通訊的,上面的子組件傳值給父組件其實也就是父組件監聽子組件的事件,而後觸發父組件的方法的,換個說法,也就是子組件調用了父組件的方法,再寫一下代碼吧:

子組件

// methods 裏
update(){
  this.$emit('update','ljy');
  // 第一個參數:事件名,第二個參數:傳遞給事件方法的參數
}

父組件

/* template 裏面的代碼,監聽子組件裏面的 update 事件,調用父組件的 childUpdate 方法

 <child :name="userName" @update="childUpdate"></child>

*/
// methods
chidlUpdate(val){
  // val 參數就是子組件傳遞過來的數據
  this.userName = val;
}

上面的代碼中,從某種意義上來講,就是子組件調用了父組件的 childUpdate 方法。

3.2 this.$paarent.event

這個就比較簡單了,咱們假設咱們在父組件定義了一個 fatherMethod() 方法,而後咱們子組件就能夠經過下面的代碼實現調用 fatherMethod() 的方法

childClick(){
  this.$parent.fatherMethod();
}

3.3 props

props 能傳遞 Function 類型的數據,因此,咱們經過 props 固然也是能夠直接的調用父組件傳遞過來的方法啦。很少說,直接擼代碼:
父組件

<!-- 假設父組件裏定義了一個 fatherMethod() 方法 -->
<child :fatherMethod="fatherMethod"></child>

子組件

props: {
  fatherMethod: {
    type: Function,
    default: null
  }
},
methods: {
  childClick() {
    this.fatherMethod();
  }
},

這樣咱們也是調用了父組件的方法啦。

4 父組件調用子組件的方法

這個,暫時沒有遇到過這種狀況,不過以備不時之需,也寫一下吧。父組件調用子組件的方法的話是利用 ref 獲取到子組件實例,從而調用子組件的方法,假設咱們子組件有這麼一個 childMethod() 方法。那麼咱們的父組件就能夠這麼來調用子組件的方法了

/* <child ref="con"></child> 子組件 */

methods: {
  update() {
    this.$refs.con.childMethod();
  },
}

至此,關於父子組件通訊的的話題就聊到這邊了,若是有啥錯誤或者遺漏的,歡迎在下面斧正啦。

相關文章
相關標籤/搜索