vue子组件修改父组件的数据

1,337 阅读1分钟

vue子组件修改父组件的数据

子组件能否修改父组件的数据?

官方文档中提到,vue的设计是单项数据流的模式,官方文档也不建议在子组件中修改props的数据,原因是:这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。,但是实际开发场景中,有一些场景确实碰到了需要在子组件中直接修改props中的数据的情况比如element的dialog,本篇本章记录一下两种在子组件中修改父组件中的数据的方法(注意:不是直接修改子组件中props的数据)

v-model实现父子组件双向数据绑定

众所周知,vue的语法中,可以直接在input,textarea等标签直接绑定v-model事项双向数据绑定,而v-model这个指令本质上就是 :value以及@change方法的二次封装,所以咱们可以利用这个思想,完成父子组件的双向数据绑定

父子组件通信常规写法:

//parentComponent
//$event为默认形参,即change事件带过来的参数,也可写为 @change="(val) => value = val"
<childComponent :value="value" @change="value = $event"> 
//childComponent
<template>
  <div class="hello" @click="change">
    {{value}}
  </div>
</template>
<script>
export default {
  props: ['value'],
  methods :{
    change() {
      this.$emit('change','改变之后的change')
    }
  }
}
</script>

v-model实现

//parentComponent
//$event为默认形参,即change事件带过来的参数,也可写为 @change="(val) => value = val"
<childComponent v-model="value"> 
//childComponent
<template>
  <div class="hello" @click="change">
    {{value}}
  </div>
</template>
<script>
export default {
  props: ['value'],
  model: {
    prop: 'value',  //这个地方就是上面那种普通写法中的:value的形式  可以取自定义名称,要跟props中的名称同步
    event: 'change' //这个地方就是上面那种普通写法中的@change的形式, 可以取自定义名称,内置处理了普通写法中父组件的赋值事件
  },
  methods :{
    change() {
      this.$emit('change','改变之后的change')
    }
  }
}
</script>

v-bind.sync实现双向数据绑定(官方提供)

2.3.0+ 新增 在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件两侧都没有明显的变更来源。

普通写法

//parentComponent
//$event为默认形参,即change事件带过来的参数,也可写为 @change="(val) => value = val"
<childComponent v-bind:title="doc.title" v-on:update:title="doc.title = $event"> 
//childComponent
<template>
  <div class="hello" @click="change">
    {{title}}
  </div>
</template>
<script>
export default {
  props: ['title'],
  methods :{
    change() {
      this.$emit('update:title', newTitle)
    }
  }
}
</script>

.sync便捷语法

//parentComponent
//$event为默认形参,即change事件带过来的参数,也可写为 @change="(val) => value = val"
<childComponent :title.sync="doc.title"> 
//childComponent
<template>
  <div class="hello" @click="change">
    {{title}}
  </div>
</template>
<script>
export default {
  props: ['title'],
  methods :{
    change() {
      this.$emit('update:title', newTitle)
    }
  }
}
</script>

注意

  • 带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model
  • 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync=”{ title: doc.title }”,是无法正常工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。