如果你不理解Vue的props传递数据是单向传递的话,你很容易想把父组件传递的值直接在子组件中改变,极其容易犯的错,如下:
父组件中:
<child-cpn :title="title"></child-cpn>
子组件中:
<template>
<div>
<button @click="sendMsg">子组件Two按钮</button>
父组件传给子组件的title:{{title}}
</div>
</template>
...
props:['title'],
methods:{
sendMsg(){
this.title = '改变了'
}
}
...
Error:你直接改了父组件传给子组件的数据,而props数据是向下传递的,会报错:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. 避免直接改变值,每当父组件重新渲染时,这个值会被重写(覆盖)。
遇到上面的问题,你首先会想到的是下面这种方案:
父组件中:
<child-cpn :title="title" @changeTitle="changeTitle"></child-cpn>
...
data(){
return{
title:'今天天气不错',
}
}
methods:{
changeTitle(val){
this.title = val
}
}
...
子组件中:
<template>
<div>
<button @click="sendMsg">子组件Two按钮</button>
父组件传给子组件的title:{{title}}
</div>
</template>
...
props:['title'],
methods:{
sendMsg(){
this.$emit('changeTitle','改变了')
}
}
...
总结:当你想在子组件中操作父组件的数据,实际上的思维方式:是通过子组件$emit携带数据发送一个事件给父组件,通过父组件来改变这个数据,本质上并没有让子组件去改父组件的数据,而是子组件借父组件的手去改变父组件的数据,以达到'子组件改了父组件值'的假象。
回过头来看看官网的:在有些情况下,需要对prop 进行“双向绑定”,官方推荐采取的是update结合.sync来处理这类问题。(sync:同步)
父组件中:
<child-cpn :title.sync="title"></child-cpn>
// 上面的写法是个简写,实际做的操作如下
// <child-cpn :title="title" @update:title="(val) => { title = val;}"></child-cpn>
子组件中:
<template>
<div>
<button @click="sendMsg">子组件Two按钮</button>
父组件传给子组件的title:{{title}}
</div>
</template>
...
props:['title'],
methods:{
sendMsg(){
this.$emit('update:title','改变了')
}
}
...
总结:最开始的做法有出处,在$emit事件中,是以update:myPropName这种事件来触发,配合父组件中.sync修饰符,不用再在父组件中写一个@事件,更简单明了。