最近在使用element-ui的dialog組件二次封裝成獨立組件使用時,子組件需要將關閉dialog狀態返回給父組件,簡單的說就是要實現父子組件之間的數據雙向綁定問題。
大致代碼如下:
1,父組件
<template>
<button @click="openDialog">打開彈窗</button>
<dialogCompenent :show="result" :result="result" @dialogData="closeDialog"></dialogCompenent>
</template>
<script type="text/babel">
import dialogCompenent from '/dialogCompenent'
export default {
data () {
return {
result: false
}
},
components: {
dialogCompenent
},
methods: {
openDialog () {
this.result = true
},
closeDialog (data) {
this.result = data
}
}
}
</script>
2,子組件 childCompenent
<template>
<el-dialog
title="彈框組件"
:visible.sync="result"
@open="doOpen"
@close="doClose"
:show="result"
size="tiny">
<div class="content-wrapper">
具體業務代碼...
</div>
</el-dialog>
</div>
</template>
<script type="text/babel">
import videoApi from '../../api/videoApi/videoApi'
export default {
name: 'dialogCompenent',
props: {
result: Boolean
},
methods: {
doOpen () {
...
},
doClose () {
this.$emit('dialogData', false)
...
}
}
}
</script>
程序在瀏覽器上雖然能夠正常運行,但是在vue2.0卻會報錯:
[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: "result" (found in component )
組件內不能修改props的值,同時修改的值也不會同步到組件外層,即調用組件方不知道組件內部當前的狀態是什么
這是什么原因造成的呢?
在vue1.x版本中利用props的twoWay和.sync綁定修飾符就可以實現props的雙向數據綁定。
在vue2.0中移除了組件的props的雙向數據綁定功能,如果需要雙向綁定需要自己來實現。
在vue2.0中組件的props的數據流動改為了只能單向流動,即只能由(父組件)通過組件的v-bind:attributes傳遞給(子組件),子組件只能被動接收父組件傳遞過來的數據,並在子組件內不能修改由父組件傳遞過來的props數據。
官方文檔解釋:
prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。這是為了防止子組件無意修改了父組件的狀態——這會讓應用的數據流難以理解。
雖然廢棄了props的雙向綁定對於整個項目整體而言是有利且正確的,但是在某些時候我們確實需要從組件內部修改props的需求
在Vue2.0中,實現組件屬性的雙向綁定方式
子組件修改:
<template>
<el-dialog
title="彈框組件"
:visible.sync="openStatus"
@open="doOpen"
@close="doClose"
:show="openStatus"
size="tiny">
<div class="content-wrapper">
具體業務代碼...
</div>
</el-dialog>
</div>
</template>
<script type="text/babel">
import videoApi from '../../api/videoApi/videoApi'
export default {
name: 'dialogCompenent',
props: {
result: Boolean
},
/*創建一個openStatus變量緩存result數據
*在子組件需要調用result的地方調用data對象openStatus
*/
data () {
return {
openStatus: this.result
}
},
//新增result的watch,監聽變更同步到openStatus
//監聽父組件對props屬性result的修改,並同步到組件內的data屬性
watch: {
result (val) {
this.openStatus = val
}
},
methods: {
doOpen () {
...
},
doClose () {
this.$emit('dialogData', false)//子組件對openStatus修改后向父組件發送事件通知
...
}
}
}
</script>
父組件修改:
<template>
<button @click="openDialog">打開彈窗</button>
<dialogCompenent :show="result" :result="result" @dialogData="closeDialog"></dialogCompenent>
</template>
<script type="text/babel">
import dialogCompenent from '/dialogCompenent'
export default {
data () {
return {
result: false
}
},
components: {
dialogCompenent
},
methods: {
openDialog () {
this.result = true
},
closeDialog (data) {
this.result = data//子組件觸發父組件事件,進行數據變更,同步result數據
}
}
}
</script>
至此,實現了子組件內數據與父組件的數據的雙向綁定,組件內外數據的同步。最后歸結為一句話就是:組件內部自己變了告訴外部,外部決定要不要變。
結語
那么為什么vue1.0還有的數據雙向綁定在vue2.0版本中反而拋棄了呢,通過上述案例我們也可以發現雙向綁定的props代碼多,不利於組件間的數據狀態管理,尤其是在復雜的業務中更是如此,所以盡量不使用這種方式的雙向綁定,過於復雜的數據處理使用vuex來進行數據管理。(https://vuex.vuejs.org/zh-cn/intro.html)