乐趣区

vue组件通信进阶

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

退出移动版