需求:父子组件同步数据
实现方式:sync或者v-model
一、sync
原理:
通常我们要父子组件中的数据时刻保持同步,可以这样:
父组件中的template:
<sycn-son :foo="fatherFoo"></sycn-son>
子组件注册foo数据:
props:{
foo: String
},
子组件改变:通过点击按钮,触发update事件,将值传入
<button @click="updateFoo">点击改变</button>
methods:{ updateFoo(){ this.$emit('update','foo被子组件改变啦') } }
父组件接收:
<sycn-son :foo="fatherFoo" v-on:update="sonFoo => fatherFoo = sonFoo"></sycn-son>
效果:
未点击:
点击改变:
父组件来点击改变:
这样就实现了父子组件同步数据,sync就是这样的原理,vue提供了sync修饰符简化了上面的代码
因此就可以这样写:
父组件:
<sycn-son :foo.sync="fatherFoo"></sycn-son>
子组件:
updateFoo(){ this.$emit('update:foo','foo被子组件改变啦') }
效果:依旧如上图
代码:
父组件:
<template> <div> <sycn-son :foo.sync="fatherFoo"></sycn-son> <br> 父组件的foo:{{fatherFoo}} <button @click="syncFatherUpdate">父组件来点击改变</button> </div> </template> <script> import sycnSon from './sycnSon' export default { name: 'sycnFather', components:{ sycnSon }, data () { return { fatherFoo:'我是一开始的foo' } }, methods:{ syncFatherUpdate (){ this.fatherFoo = '被父组件改变' } } } </script>
子组件:
<template> <div> 子组件的foo:{{foo}} <button @click="updateFoo">点击改变</button> </div> </template> <script> export default { name: 'sycnSon', props:{ foo: String }, methods:{ updateFoo(){ this.$emit('update:foo','foo被子组件改变啦') } } } </script>
注意:
当sync修饰的prop是个对象或者数组,虽然对象/数组是引用类型的,你直接修改子组件,会同时修改父组件的数据,但是会让数据流变得更加难以分析!所以要深度复制对象给一个新值,再改变新值传给父组件。
JSON.parse(JSON.stringify(this.analysisData))
二、v-model---只介绍父子组件双向绑定
v-model通常用于表单元素的双向绑定,v-model 是 .sync的一种体现。约定俗成是用于表单类型的双向绑定。可不可以用于其他的组件呢,当然可以,只是没有sync这么直观
1. 表单类型的双向绑定:
子组件:
<input :value="value" @input="$emit('input', $event.target.value)">
@input是自带的oninput事件,当输入框改变时,调用里面的事件。
父组件:
<model-son v-model="fatherMsg"></model-son>
相当于:
效果:
未改变输入框:
改变输入框:
点击父组件来点击改变:
完整代码:
父组件:
<template> <div> <model-son v-model="fatherMsg"></model-son> <br> 父组件:{{fatherMsg}} <button @click="modelFatherUpdate">父组件来点击改变</button> </div> </template> <script> import modelSon from './modelSon' export default { name: 'modelFather', components:{ modelSon }, data () { return { fatherMsg:'父组件一开始定义的fatherMsg' } }, methods:{ modelFatherUpdate (){ this.fatherMsg = 'fatherMsg被父组件改变' } } } </script>
子组件:
<template> <div> 子组件的msg: <input :value="value" @input="$emit('input', $event.target.value)"> </div> </template> <script> export default { name: 'modelSon', // 必须是value props:{ value:String }, } </script>
注意:注册必须是value
2.自定义组件v-model双向绑定
官网:
子组件:首先要注册,和说明model
model: { prop: 'msg', event: 'change' }, props:{ msg:String },
使用model解释:prop属性说,我要将msg作为该组件被使用时v-model能取到的值,也就是一开始的值
event说,我emit ‘change’ 的时候,传入的参数值就是父组件v-model要收到的值。
父组件:使用v-model绑定自己的数据
<model-son v-model="fatherMsg"></model-son>
效果:
未点击时:
点击改变:
父组件来点击改变:
完整代码:
父组件:
<template> <div> <model-son v-model="fatherMsg"></model-son> <br> 父组件:{{fatherMsg}} <button @click="modelFatherUpdate">父组件来点击改变</button> </div> </template> <script> import modelSon from './modelSon' export default { name: 'modelFather', components:{ modelSon }, data () { return { fatherMsg:'父组件一开始定义的fatherMsg' } }, methods:{ modelFatherUpdate (){ this.fatherMsg = 'fatherMsg被父组件改变' } } } </script>
子组件:
<template> <div> 子组件的msg:{{msg}} <button @click="modelUpdate">点击改变</button> </div> </template> <script> export default { name: 'modelSon', model: { prop: 'msg', event: 'change' }, props:{ msg:String }, methods:{ modelUpdate (){ this.$emit('change','msg被子组件改变了!') } } } </script>
待补充。。。