vue2 中实现双向数据绑定的方式有两种,一个是v-model,一个是.sync修饰符。它们的区别是一个标签或者组件上,v-model只能使用一次,而.sync修饰符可以使用多次。

在Vue中,子父组件最常用的通信方式就是通过props进行数据传递,props值只能在父组件中更新并传递给子组件,在子组件内部,是不允许改变传递进来的props值,这样做是为了保证数据单向流通。但有时候,我们会遇到一些场景,需要在子组件内部改变props属性值并更新到父组件中,这时就需要用到.sync修饰符。

以下面例子为例:

Father.vue

<template>
  <div class="hello" style="background-color: azure;">
    --------------Farther-------------<br>
    {{ msg }}
    <button @click="handleMsg">changeMsg</button>
    <Child :msg="msg" />
  </div>
</template>

<script>
import Child from '../views/Child.vue';
export default {
  name: 'Father',
  components: {
    Child
  },
  data() {
    return {
      msg: 'unchanged msg',
    }
  },
  methods: {
    handleMsg() {
      this.msg = "The news of the father's change"
    }
  }
}
</script>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

Child.vue

<template>
  <div class="hello">
    --------------Child----------------<br/>
    {{ msg }}
    <button @click="handleMsg">changeMsg</button>
  </div>
</template>

<script>
export default {
  name: 'Child',
  props: {
      msg: String,
  },
  methods: {
    handleMsg() {
      // eslint-disable-next-line vue/no-mutating-props
      this.msg = "The news of the child's change"
    }
  }
}
</script>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

vue2 中的 .sync 修饰符_前端

点击子组件的 changeMsg,消息变更,但是控制台报错

vue2 中的 .sync 修饰符_vue.js_02

vue2 中的 .sync 修饰符_数据绑定_03

另一个环境下,也报错但是只有子组件消息变更

vue2 中的 .sync 修饰符_javascript_04

使用 .sync 时

Father.vue

<Child :msg.sync="msg" />
  • 1.

 Child.vue

handleMsg() {
      this.$emit('update:msg', "The news of the child's change");
    }
  • 1.
  • 2.
  • 3.

点击后,消息变更,并且控制台没有报错。 

vue2 中的 .sync 修饰符_javascript_05

.sync 修饰符实现原理

.sync 修饰符也是一种语法糖,用于实现双向数据绑定,但它的实现方式与 v-model 有所不同。

当使用 :msg.sync="msg" 时,等价于 :msg="msg" @update:msg="msg = $event"
父组件使用 :msg.sync 将属性传递给子组件,并监听 update:msg 事件。子组件使用 $emit('update:msg', newValue) 来更新父组件的属性。

因为是在父组件更新值,所以就不是在子组件更新 prop 值了。

Father.vue

<Child :msg="msg" @update:msg="childMsg"/>
childMsg() {
  this.msg = "The news of the child's change"
}
  • 1.
  • 2.
  • 3.
  • 4.

Child.vue

<button @click="handleMsg">changeMsg</button>
handleMsg() {
  this.$emit('update:msg', "The news of the child's change");
}
  • 1.
  • 2.
  • 3.
  • 4.

v-model 实现原理

v-model 是一种语法糖

当使用 v-model="msg" 时,等价于 :msg="msg" @input='msg=$event'
父组件使用 :msg="msg" 将属性传递给子组件,并监听 input 事件。子组件使用 props 的 value 属性接收值,并使用 $emit('input ', newValue) 来更新父组件的属性。

 Father.vue

<template>
  <div class="hello" style="background-color: azure;">
    --------------Farther-------------<br>
    {{ msg }}
    <button @click="handleMsg">changeMsg</button>
    <Child v-model="msg"/>
  </div>
</template>

<script>
import Child from '../views/Child.vue';
export default {
  name: 'Father',
  components: {
    Child
  },
  data() {
    return {
      msg: 'unchanged msg',
    }
  },
  methods: {
    handleMsg() {
      this.msg = "The news of the father's change"
    }
  }
}
</script>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

Child.vue

<template>
  <div class="hello">
    --------------Child----------------<br/>
    {{ value }}
    <button @click="handleMsg">changeMsg</button>
  </div>
</template>

<script>
export default {
  name: 'Child',
  props: {
    value: String,
  },
  methods: {
    handleMsg() {
      this.$emit('input', "The news of the child's change");
    }
  }
}
</script>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

等同于

<Child :value="msg" @input="msg=$event"/>
  • 1.

在Vue2中,一个组件只能有一个v-model。 .sync 支持多个props的双向绑定

Vue3中,v-model支持参数化绑定,替代.sync的功能,例如:

<child v-model:name="userName" v-model:age="userAge" />
  • 1.

Vue 3中不再推荐使用.sync,转而用带参数的v-model。