前言 在 Vue 項目中父子組件的通信是非常常見的,最近做項目的時候發現對這方面的知識還不怎么熟練,在這邊做一下筆記,系統學習一下吧。
1 父組件傳值給子組件
1.1 傳值寫法
父組件傳值給子組件,這個就比較常見了,直接用 props 就可以了。但是就算是 props 子組件那邊也有三種寫法,如下面代碼所示:
父組件
子組件
// 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 會在瀏覽器的控制臺中發出警告。
所以啊,如果你不只是想在子組件中簡單的渲染父組件傳過來的值的話,那么可以用下面的兩種方法。
-
這個 prop 用來傳遞一個初始值;
這個子組件接下來希望將其作為一個本地的 prop 數據來使用。在這種情況下,最好定義一個本地的 data 屬性并將這個 prop 用作其初始值:
props: ['name'],
data() {return {userName:this.name,};
},
-
這個 prop 以一種原始的值傳入且需要進行轉換。
在這種情況下,最好使用這個 prop 的值來定義一個計算屬性:
props: ['name'],
computed: {userName(){return this.firstName + this.name}
},
2 子組件傳值給父組件
雖然我們說是要單向數據流,但是很多時候,我們在子組件改變了某些值之后,還是要反饋給父組件,讓父組件做一下修改,那么這個時候就要想著子組件向父組件傳值啦。有下面這么兩種方式
2.1 emit 方法
這個基本都是用 emit 來傳遞了,用法直接看代碼吧:
子組件
// props:['name]// methods 里
update(){this.$emit('update','ljy');// 第一個參數:事件名,第二個參數:傳遞給事件方法的參數
}
父組件
/* 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
修飾符。看代碼吧:
上面的代碼和前面的代碼是一個效果,是不是方便了很多。舒服了吧。
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 當然也是可以直接的調用父組件傳遞過來的方法啦。不多說,直接擼代碼:
父組件
子組件
props: {fatherMethod: {type: Function,default: null}
},
methods: {childClick() {this.fatherMethod();}
},
這樣我們也是調用了父組件的方法啦。
4 父組件調用子組件的方法
這個,暫時沒有遇到過這種情況,不過以備不時之需,也寫一下吧。父組件調用子組件的方法的話是利用 ref 獲取到子組件實例,從而調用子組件的方法,假設我們子組件有這么一個 childMethod()
方法。那么我們的父組件就可以這么來調用子組件的方法了
/* <child ref="con"></child> 子組件 */methods: {update() {this.$refs.con.childMethod();},
}
至此,關于父子組件通信的的話題就聊到這邊了,如果有啥錯誤或者遺漏的,歡迎在下面斧正啦。
原文地址:https://segmentfault.com/a/1190000017346476