Vue 中 .sync 修饰符的作用

740 阅读2分钟

.sync 修饰符

.sync 修饰符相对来说比较特殊,因为其不是事件 event 原有的事件处理相关函数的演变,而是 Vue 自己定义的一个修饰符,如上述的修饰符分类中也将 .sync 分类为自定义事件的修饰符,那么这个自定义事件到底是什么事件呢?

这个事件对应的是 eventBus 事件,eventBus 事件是 MVC 中的一个模式,简单来说就是发布和订阅的过程,就是说有两方,甲方负责始终监听某个事件,乙方负责在需要的时候触发这个事件,甲方在监听到事件被触发时就执行某些操作。甲方就是订阅,乙方就是发布,双方就是发布和订阅模式。

一个常见的情景:

子组件接受来自父组件的外部数据,而Vue 规定组件不可修改其外部数据 props,那么如何才能修改呢?

【例】: 子组件有外部数据cData,将父组件的pData传给cData,预期在点击子组件的按钮时,使cData的值减少100

子组件:

<template>
    {{cData}}
    <button @click="???">修改cData</button> // ???处该如何填
</template>

<script>
export default {
    props: ["cData"]
}
</script>

父组件:

<template>
    <div>
        {{pData}}
        <Child :cData="pData" />
    </div>
</template>

<script>
import Child from './Child.vue'
export default {
    data(){
        return {
            pData: 1000
        }
    },
    components: {Child}
}
</script>

由于不可修改子组件的cData,只能想办法让父组件修改pData。

首先,我们让子组件在点击按钮时触发一个事件'update:cData',这可以用vm.$emit方法实现:

<button @click="$emit('update:cData', cData - 100)">修改cData</button>
//$emit 方法第一个参数为事件名,第二个参数为要传出的值,此处将传出值设为 cData - 100

此时,** vm.$event ** 便记录了cData - 100的值(即cData的预期修改值)

然后,在父组件监听此事件,将pData改为vm.$event即可:

<Child :cData="pData" v-on:update:cData="pData = $event" />

** .sync 修饰符进行简化: **

由于这样的写法很麻烦,而类似的情景又很常见,所以 Vue 提供了.sync修饰符简化写法。 在给cData传值时加上.sync即可(前提是要将$emit触发的事件名取为'update:cData'):

<Child :cData.sync="pData" />

总结

Vue 的组件在接受外部数据 props 时,Vue 规定,子组件在通过 props 接受外部数据后只有使用该数据的权利,但没有修改该属性的权利。因为,如果子组件修改了外部传来的数据,这样一来子组件和使用其的父文件都可以改来改去,在父组件和子组件都没有明显的改动来源,到最后都不知道这个数据是谁改的了,数据就不好控制了。因此 Vue 就规定组件只能有权使用 props 的属性,不得自己改变,那么若其想要改变,就必须通知该数据的真正拥有者改变,也就是使用该组件的父文件。

所以通过 .sync 修饰符的操作原理:

  1. 组件不能修改 props 外部数据
  2. this.$emit 可以触发事件,并传参
  3. event可以获取event 可以获取 emit 的参数

代码<my-comp :foo.sync="bar"></my-comp>会被扩展成<comp :foo="bar" @update:foo="val => bar = val"></comp>,就是一个语法糖。