组件之间的双向绑定

最近在学习electron+vue仿有道云笔记markdown区域的代码中,遇到父组件与子组件数据需要同步变化的问题。

(可以利用组件间的v-model或者.sync修饰符)故做此总结。

利用 v-model

通常子组件更新某个变量并需要告知父组件时,需要子组件$emit触发事件,然后父组件$on监听该事件再去改变值。可以利用v-model的使用原理来使组件之间利用v-model进行双向绑定。

  1. 父组件通过v-model绑定一个变量传给子组件

  2. 子组件通过props['value']接收。注意是value

  3. 子组件通过$emit('input',XX)去改变父组件中v-model绑定的变量。注意是input事件

v-model 原理

Vue根据元素决定如何监听和处理数据。对于input元素,您可以这样使用v-model

<input v-model="email" />

v-model 翻译成这样:

<input :value="email" @input="(e) => (email = e.target.value)" />

v-model 实现方案

// 子组件
<template>
  <input @input="handleInput" /> //
  这个事件不一定是input事件,只要可以改变content值的事件就可以
</template>

<script>
export default {
  name:'BasicInput',
  prop: ['value'],
  data () {
    return {
      content: this.value
    }
  },
  methods: {
    handleInput (e) {
      this.$emit('input', this.content) // 这个事件名字一定得失input事件
    }
  }
}
</script>
// 父组件
<basic-input v-model="email"></basic-input>

实现方案如上。

定制 v-model 的 prop 和 event

因为有时候value或者input需要作其他的用处,这个时候就可以定制其他变量来做啦。

// 子组件
export default {
  model: {
    prop: "hidden",
    event: "blur",
  },
  props: ["hidden"], //此处不能漏掉
  methods: {
    handleInput(val) {
      this.$emit("blur", val);
    },
  },
};
// 父组件
<basic-input v-model="email" />

vue 自动将其转换为:

<basic-input :hidden="email" @bulr="(e) => (email = e.target.value)" />

v-model 与.sync 区别

v-model 本质

<!--v-model写法-->
<my-component type="text" v-model="value">
<!--展开语法糖后的写法-->
<my-component type="text"
  :value="value"
  @input="value = $event.target.value"
>
<!--
默认针对原生组件input事件,但是如果子组件定义了针对事件
model: {
        prop: "value",
        event: "update"
},
则编译为
-->
<my-component type="text"
  :value="value"
  @update="(val) => value = val"
>

.sync 本质

<!--语法糖.sync-->
<my-component :value.sync="value" />
<!--编译后的写法-->
<my-component
  :value="msg"
  @update:value="(val) => value = val"
>

总结:两者本质是一样的,并没有任何区别:"监听一个触发事件"="(val) => value = val"

区别

  • 只不过v-model默认对应的是input或者textarea等组件的input事件,如果在子组件利用update替换这个input事件,其本质和.sync修饰符一模一样。比较单一,不能有多个。
// 子组件可以用自定义事件,来替换v-model默认对应的原生input事件,只不过我们需要在子组件手动 $emit
model: {
        prop: "value",
        event: "update"
},
  • 一个组件可以多个属性用.sync修饰符,可以同时”双向绑定多个prop,而并不像v-model那样,一个组件只能有一个。