.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 修饰符的操作原理:
- 组件不能修改 props 外部数据
- this.$emit 可以触发事件,并传参
- emit 的参数
代码<my-comp :foo.sync="bar"></my-comp>会被扩展成<comp :foo="bar" @update:foo="val => bar = val"></comp>,就是一个语法糖。