注意: 子組件不能直接修改prop過來的數據,會報錯
方案一:
-
用data對象中創建一個props屬性的副本
-
watch props屬性 賦予data副本 來同步組件外對props的修改
-
watch data副本,emit一個函數 通知到組件外
HelloWorld組件代碼如下:(代碼里面有相應的注釋)
<template><div class="hello"><h1 v-show="visible">測試顯示隱藏</h1><div @click="cancel">點我點我</div></div>
</template><script>
export default {name: 'HelloWorld',props: {value: {type: Boolean,default:false}},data () {return {visible: false}},watch:{value(val) {this.visible = val;},// 只有這一步 才觸發父組件的方法 由父組件的 paretnVisibleChange 方法去改變父組件的數據visible(val) { this.$emit("paretnVisibleChange",val); } },// 子組件修改的只能是子組件 本身的data數據methods:{cancel(){this.visible = !this.visible;}},
// 注意這段代碼 為了同步父組件的數據mounted() {if (this.value) {this.visible = true;}}
}
</script>
<style scoped></style>
父組件代碼如下:
<template><div id="app"><HelloWorld :value = 'visible' @paretnVisibleChange="visibleChange" /></div>
</template><script>
import HelloWorld from './components/HelloWorld'export default {name: 'App',components: {HelloWorld},data () {return {visible: true}},methods:{// 父子組件就是靠的這個方法改變數據的visibleChange(val){this.visible = val;}}
}
</script>
方案一 的缺點就是 父組件必須有個?visibleChange?這樣的方法,有點累贅。
?
這時候 想到了 v-model?
因為
<input v-model = 'someThing'>
是下面這段代碼的語法糖
<input :value = 'someThing' @input = 'someThing = $event.target.value'>
也就是說 v-mode 自帶了 一個改變父組件的方法 類似方案一的 ??paretnVisibleChange
但是使用 v-model 的時候 需要注意兩點:
1. 子組件要接受 ?value ?屬性
2. value改變時 要觸發input 事件
?
方案二:
HelloWorld 子組件的代碼如下;
<div class="hello"><h1 v-show="visible">測試顯示隱藏</h1><div @click="cancel">點我點我</div></div>
</template><script>
export default {name: 'HelloWorld',props: {value: {type: Boolean,default:true}},data () {return {visible: false}},watch:{value(val) {this.visible = val;},// 子組件 改變的就是這段代碼visible(val) {this.$emit("input",val);}},methods:{cancel(){this.visible = !this.visible;}},mounted() {if (this.value) {this.visible = true;}}
}
</script>
父組件代碼如下:(父組件省去了 paretnVisibleChange 方法)
<template><div id="app"><HelloWorld v-mode = 'visible'/></div>
</template><script>
import HelloWorld from './components/HelloWorld'export default {name: 'App',components: {HelloWorld},data () {return {visible: true}}
}
</script>
方案三:
vue 2.3.0之后新增了 .sync 屬性 使用方法跟 v-model ?類似 具體 請參考 :?https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修飾符
下面我寫了一個簡單的sync 的使用實例:
父組件的代碼如下:
?
<liis="DragCompent"v-for="(item, index) in layoutItem":item="item"v-model="cloneLeftItemText":leftDragItemIsDraged.sync = 'leftDragItemIsDraged':key="index"></li>
子組件的代碼如下:
props: {leftDragItemIsDraged: {type: Boolean,default: false}},
watch:{leftDragItemIsDraged(val) {this.thisLeftDragItemIsDraged = val;
},
thisLeftDragItemIsDraged(val){this.$emit('update:leftDragItemIsDraged', val)
}
}
?
效果如下:
?