序言:我们都知道 vue 父子组件通信主要通过 props 和事件,那还知道其他形式的通讯方式吗?本文将一一为你揭晓。
1、sync 修饰符 +this.$emit(‘update: 属性名 ’, data)
1.1、sync 修饰符的作用
在 Vue 中,子父组件最常用的通信方式就是通过 props 进行数据传递,props 值只能在父组件中更新并传递给子组件,在子组件内部,是不允许改变传递进来的 props 值,这样做是为了保证数据单向流通。但有时候,我们会遇到一些场景,需要在子组件内部改变 props 属性值并更新到父组件中,这时就需要用到.sync 修饰符。
如果我们在子组件中直接修改 props 中的属性值,将会报以下错误:
报错的大概意思就是:不允许直接修改 props 里面的属性值。
这里可以参考一篇文章:https://blog.csdn.net/XuM2222…
1.2、利用 sync 修饰符实现双向数据绑定
父组件:通过给绑定属性添加 sync 修饰符将值传递给子组件,父组件值改变,子组件随着改变。
子组件:通过 this.$emit(‘update: 属性名 ’, data) 来改变 props 属性值并更新父组件对应的值。
<template>
<div @click="click2change">
点击加一 {{foo}}
<my-checkbox :checked.sync="foo"></my-checkbox>
</div>
</template>
<script>
import Vue from 'vue';
// 组件通信:props,事件,provide|inject,vuex,vuebus,。。。const myCheckbox = Vue.component('my-checkbox', {
props: {
value: {
type: String,
default: 'testvalue'
},
checked: {
type: Number,
default: 0
}
},
methods: {changeValue() {
//this.checked -= 2;// 会报刚刚说的错误,不能直接修改 props 属性值
this.$emit("update:checked", this.checked - 2);
}
},
template: `
<div>
<div @click.stop="changeValue">checked: {{checked}}</div>
</div>
`
});
export default {
name: 'list',
components: {myCheckbox,},
data() {
return {foo: 1}
},
methods: {click2change() {this.foo += 1;}
}
}
</script>
结果运行:
2、自定义组件 v -model+this.$emit(‘ 自定事件名 ’, data)
2.1、v-model 语法糖
2.2、自定义组件 v -model
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。model 选项可以用来避免这样的冲突:
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {checked: Boolean},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
现在在这个组件上使用 v-model 的时候:
<base-checkbox v-model="lovingVue"></base-checkbox>
这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。
注意 :你仍然需要在组件的 props 选项里声明 checked 这个 prop。
2.3、使用自定义组件 v -model 实现双向数据绑定
父组件:通过 v -model 向子组件传值,并监听自定义函数更新值。
子组件:通过 model 选项自定义绑定属性名和方法,使用 $emit 触发自定义方法更新父组件的值。
<template>
<div @click="click2change">
点击加一 {{foo}}
<my-checkbox v-model="foo"></my-checkbox>
</div>
</template>
<script>
import Vue from 'vue';
// 组件通信:props,事件,provide|inject,vuex,vuebus,。。。const myCheckbox = Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
// 需要在组件的 props 选项里声明 checked 这个 prop
checked: {
type: Number,
default: 0
}
},
methods: {changeValue() {this.$emit("change", this.checked - 1);
}
},
template: `
<div>
<div @click.stop="changeValue">checked: {{checked}}</div>
</div>
`
});
export default {
name: 'list',
components: {myCheckbox,},
data() {
return {foo: 1}
},
methods: {click2change() {
// debugger
this.foo += 1;
}
}
}
</script>
运行结果:
3、value 方式 +this.$emit(‘input’, data)
这种方式实现双向数据绑定是基于 v -model 语法糖
<template>
<div @click="click2change">
点击加一 {{foo}}
<my-checkbox v-model="foo"></my-checkbox>
</div>
</template>
<script>
import Vue from 'vue';
// 组件通信:props,事件,provide|inject,vuex,vuebus,。。。const myCheckbox = Vue.component('my-checkbox', {
props: {
value: {
type: Number,
default: 0
}
},
methods: {changeValue() {this.$emit("input", this.value - 1);
}
},
template: `
<div>
<div @click.stop="changeValue">value: {{value}}</div>
</div>
`
});
export default {
name: 'list',
components: {myCheckbox,},
data() {
return {foo: 1}
},
methods: {click2change() {
// debugger
this.foo += 1;
}
}
}
</script>
运行结果:
4、总结
无论是上面哪种双向数据绑定的方式,基本原理还是基于 props 和事件,只是形式上的改变,本质没有变。