對于使用Vue的新手來說,組件之間的數據傳遞是一個比較麻煩的問題,在開發中我自己也踩了不少坑,這篇文章簡單地做了一個總結。
首先,在 Vue 中,父子組件的關系可以總結為 props down, events up。父組件通過 props 向下傳遞數據給子組件,子組件通過 events 給父組件發送消息。如下圖:
目錄
- 1. 父子組件之間的數據傳遞
- 1.1 父組件向子組件傳遞數據
- 1.2 子組件向父組件傳遞事件
- 2. 非父子關系組件之間的數據傳遞
父子組件之間的數據傳遞
父組件向子組件傳遞數據
組件實例的作用域(scope)是孤立的,所以組件之間無法相互訪問到對方的數據,所以這里我們需要在子組件中使用props
選項去接受來自父組件傳遞進來的動態數據,并且在父組件的標簽上綁定v-bind該數據,這樣一來,我們就把父組件中的數據傳遞給了子組件中。
// 創建父組件
Vue.component("m-super", {
data: ()=>{
return {
message: "Hello Super"
}
},
template: `<div>
<input placeholder='請輸入message的值' v-model='message'></input>
<br/>
<m-child :message='message'></m-child>
</div>`
});
// 創建子組件,并需要把父組件的message的值傳遞給子組件
Vue.component("m-child", {
props: ["message"],
template: "<span>子組件顯示:{{ message }}</span>"
})
props
數據是單向傳遞
props
是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。
這是為了防止子組件無意修改了父組件的狀態——這會讓應用的數據流難以理解。
每次父組件更新時,子組件的所有 prop 都會更新為最新值。這意味著你不應該在子組件內部改變 prop。如果你這么做了,Vue 會在控制臺報錯。如下:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "message"
子組件向父組件傳遞事件
因為prop
是單向數據流的,所以prop接受的數據是無法雙向綁定的,那么如何改變父組件的數據呢——使用vue
的自定義事件。
- 子組件中我們可以通過$emit(eventName)來觸發事件
- 父組件中我們可以通過$on(eventName)來監聽事件
下面給子組件添加了一個重置按鈕,一按就可以將父組件的值改為Hello Child
。代碼如下:
// 創建父組件
Vue.component("m-super", {
data: ()=>{
return {
message: "Hello Super"
}
},
template: `<div>
<input placeholder='請輸入message的值' v-model='message'></input>
<br/>
<m-child :message='message' v-on:reset="reset"></m-child>
</div>`,
methods:{
reset:function(e){
this.message = e
}
}
});
// 創建子組件,并需要把父組件的message的值傳遞給子組件
Vue.component("m-child", {
props: ["message"],
template: "<div><span>子組件顯示:{{ message }}</span><br/><button v-on:click='reset()'>重置</button></div>",
methods: {
reset:function(){
this.$emit("reset", "Hello child")
}
}
})
這樣一來,我們便實現了父子組件數據的雙向綁定。
非父子組件之間的數據傳遞
對于非父子組件通信情況,在簡單的場景下,可以使用一個空的Vue
實例作為中央事件總線:
var bus = new Vue()
// 觸發組件 A 中的事件
bus.$emit('id-selected', 1)
// 在組件 B 創建的鉤子中監聽事件
bus.$on('id-selected', function (id) {
// ...
})
如果非父子組件通信比較復雜時,我們可以通過Vuex來解決。