序言:我们都知道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和事件,只是形式上的改变,本质没有变。