最近做了一个完整的vue项目,对父子组件之间的数据传递新的用法有了更深的了解,现在记录一下。
虽然标题是实现props 双向数据绑定 其实VUE是 不支持props数据双向绑定的,但是我们可以模拟双向绑定的样式,主要是为了简化数据更改及父子节点之前数据同步的操作。
第一种方式 v-model 的方式。
原理:利用v-model指令把数据绑定到子组件中,然后子组件中模拟普通文本框的input事件,来传递修改之后的值。
v-model的双向数据绑定的基本原理就是监听了文本框的input事件,通过监听input事件得知数据被修改了,所以我们可以触发自定义input事件,这样v-model这个指令就能监听到数据的变化。
例子:
//Parent.vue <template> <div class="box"> <p>发给child的modelMSG: {{modelMSG.msg}}</p> <p> 修改modelMSG: <input type="text" v-model="modelMSG.msg" /> </p> <Child v-model="modelMSG" /> </div> </template> <script> import Child from './Child' export default { name: 'Parent', components: { Child, }, data() { return { modelMSG: {//这里故意写成对象格式的,目的是表明v-model可以传递对象,这样就可以传递多种数据了 msg: '发给Child的modelMSG信息', }, name: 'Parent的名字', } }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } .green { color: #42b983; } .box { text-align: left; width: 600px; margin: 0 auto; } input { width: 200px; height: 35px; line-height: 35px; } </style>
注意: v-model="modelMSG" 这里的modelMSG我是故意写成对象格式的,目的是为了表明v-model可以传对象过去,这样就可以传递多个数据了。
//Child.vue <template> <div class="hello"> <p class="red">来自Parent的value: {{value.msg}}</p> <p> <input v-model="parentModelMSG" type="text" /> </p> </div> </template> <script> export default { name: 'Child', props: { value: Object, //注意子组件接收数据时用value接收,这里的value代表 parentModelMSG }, data() { return { name: '', parentModelMSG: this.value.msg, } }, watch: { parentModelMSG() { this.$emit('input', { //这里也是必要的,目的是子组件修改数据的时候回传到父组件 msg: this.parentModelMSG, }) }, 'value.msg1'() { //这块是为了监听父组件变化的时候同步parentModelMSG信息,也可以用deep的方式 value: {deep: true, handler(){ ... }},这样可以监听所有数据修改 this.parentModelMSG = this.value.msg }, }, } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } .red { color: #f00; } </style>
注意:v-model设置的属性接收时需要用value这个字段接收
第二种 .sync 的方式
原理:这其实就是普通传递数据和监听事件的一种简写方式而已, 这个方式可以算是官方给出的一种props双向绑定的一种解决方案
例子:
//Parent.vue <template> <div class="box"> <p>发给child的modelMSG: {{modelMSG.msg}}</p> <p> 修改modelMSG: <input type="text" v-model="modelMSG.msg" /> </p> <Child :data.sync="modelMSG" /> //这里:data.sync其实就是 :data="modelMSG" @update:data="(value) => { this.data = value }" </div> </template> <script> import Child from './Child' export default { name: 'Parent', components: { Child, }, data() { return { modelMSG: { msg: '发给Child的modelMSG信息', }, name: 'Parent的名字', } }, } </script>
//Child.vue <template> <div class="hello"> <p class="red">来自Parent的value: {{data.msg}}</p> <p> <input v-model="parentModelMSG" type="text" /> </p> </div> </template> <script> export default { name: 'Child', props: { data: Object, }, data() { return { name: '', parentModelMSG: this.data.msg, } }, watch: { parentModelMSG() { this.$emit('update:data', { //注意这个事件的格式是`update:${属性名}`这个属性名就是props那个key msg: this.parentModelMSG, }) }, data: { //data改变的时候同步到子组件 deep: true, handler(value) { this.parentModelMSG = value.msg }, }, }, } </script>
这是我根据经验总结出来的,可能会有不准确的地方,大家可以根据自己的理解使用。