注意: 子組件不能直接修改prop過來的數據,會報錯html
方案一:vue
用data對象中建立一個props屬性的副本app
watch props屬性 賦予data副本 來同步組件外對props的修改ide
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>
父組件代碼以下:ui
<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 這樣的方法,有點累贅。this
這時候 想到了 v-model spa
由於code
<input v-model = 'someThing'>
是下面這段代碼的語法糖
<input :value = 'someThing' @input = 'someThing = $event.target.value'>
也就是說 v-mode 自帶了 一個改變父組件的方法 相似方案一的 paretnVisibleChange
可是使用 v-model 的時候 須要注意兩點:
1. 子組件要接受 value 屬性
2. value改變時 要觸發input 事件
方案二:
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: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 的使用實例:
父組件的代碼以下:
<li is="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) } }
效果以下: