在Vue2.X中,父子組件之間有兩點(diǎn)非常重要的通信原則:
-
父子組件是單向數(shù)據(jù)流,父組件的狀態(tài)更新,子組件中prop的狀態(tài)也會(huì)更新,但是子組件的狀態(tài)變化不會(huì)影響父組件。在子組件中修改prop的狀態(tài),會(huì)在console中報(bào)錯(cuò)。關(guān)于單向數(shù)據(jù)流,Vue文檔中是這樣來(lái)描述原因的:
這是為了防止子組件無(wú)意間修改了父組件的狀態(tài),來(lái)避免應(yīng)用的數(shù)據(jù)流變得難以理解。
有一點(diǎn)應(yīng)該注意,如果父組件傳遞給子組件的狀態(tài)是
對(duì)象或者數(shù)組,因?yàn)閮烧呤前匆脗髦?,所以在子組件中是可以改變對(duì)象和數(shù)組中的值的,同時(shí)也會(huì)影響到父組件的狀態(tài)。 每次父組件狀態(tài)更新時(shí),父組件的所有雙向綁定的model都會(huì)進(jìn)行更新;同時(shí),子組件的所有 prop 也會(huì)進(jìn)行更新。這里要注意,父組件中更新的狀態(tài),必須在父組件中進(jìn)行了雙向綁定,或者傳遞到了子組件,才會(huì)觸發(fā)父組件的其他狀態(tài)的更新。
如果希望在子組件中改變父組件的狀態(tài),有兩種方式:
- 其一是通過(guò)事件派發(fā),父組件響應(yīng)子組件派發(fā)的事件,由父組件自己改變自己的狀態(tài)
- 其二是父組件向子組件傳遞
數(shù)組或者對(duì)象,在子組件中改變數(shù)組或者對(duì)象的狀態(tài)
因?yàn)閂ue的雙向數(shù)據(jù)綁定是基于Object.defineProperty()來(lái)劫持屬性的setter和getter方法,由于js的限制,如果某一個(gè)組件的狀態(tài)是一個(gè)數(shù)組,對(duì)數(shù)組的修改無(wú)法通過(guò)Object.defineProperty()劫持到,所以無(wú)法把狀態(tài)的更新反饋到視圖上。舉一個(gè)例子,下面是一個(gè)Vue單文件組件,當(dāng)我點(diǎn)擊按鈕的時(shí)候,視圖無(wú)法更新。
<template>
<div id="header-ctn">
hello {{msg[0]}}
<button @click="change">點(diǎn)我改變組件狀態(tài)</button>
</div>
</template>
<script>
export default {
data () {
return {
msg: ['yanbin', 'bluestrings']
}
},
mounted () {
},
methods: {
change () {
this.msg[0] = '閆斌';//應(yīng)該寫成 this.$set(this.msg, 0, "閆斌");
}
}
}
</script>
所以Vue提供了操作數(shù)組的方法來(lái)解決這個(gè)問(wèn)題:
Vue.set(array, pos, newVal);
但是在很多實(shí)際的case中,即使沒(méi)有用Vue.set這個(gè)方法來(lái)操作數(shù)組,我們發(fā)現(xiàn)數(shù)組的變化依然反饋到了視圖上,這是什么原因呢?這里就要提到剛才說(shuō)到的一點(diǎn),如果當(dāng)前組件的某一個(gè)狀態(tài)發(fā)生更新,Vue會(huì)強(qiáng)制自動(dòng)刷新其他綁定的狀態(tài),也就是說(shuō)組件狀態(tài)反饋到視圖上的這個(gè)操作是Vue自動(dòng)執(zhí)行的,而不再是通過(guò)Object.defineProperty()來(lái)劫持的。拿剛才的例子修改一下:
<template>
<div id="header-ctn">
hello {{msg[0]}}<br/>
今天{{day}}
<button @click="change">點(diǎn)我改變組件狀態(tài)</button>
</div>
</template>
<script>
export default {
data () {
return {
msg: ['yanbin', 'bluestrings'],
day: '星期天'
}
},
mounted () {
},
methods: {
change () {
this.msg[0] = '閆斌';
this.day = '星期一';
}
}
}
</script>
<style lang="less">
</style>
因?yàn)樾薷牧私M件的狀態(tài)day,所以Vue將msg這個(gè)數(shù)組的更新也反饋到了視圖上。