.sync修饰符是Vue提供的语法糖,它会被扩展成修改父组件属性的监听器。应用场景是在父子组件传值,且子组件要修改这个数据的时候使用。在Vue中有一条规定,组件不能直接修改props外部传来的数据,合理的做法是子组件通知父组件,由父组件进行数据的修改。它的原理是利用EventBus,子组件触发事件,父组件响应事件并实现数据的更新。
用一个通俗的例子来解释,孩子向爸爸借钱,爸爸并不会直接把钱交给孩子随意支配,而是告诉孩子我手头上有这么多钱,你需要花钱的时候通知我需要支付的金额,我帮你付款。
用一段代码来模拟上面的场景
子组件
<template>
<div class="child">
<button @click="$emit('update:money', money - 100)">
<span>我要花100块钱买玩具</span>
</button>
</div>
</template>
<script>
export default {
props: ["money"],
};
</script>
父组件
<template>
<div class="app">
<!-- $event接收事件抛出的值 -->
<Child :money="total" v-on:update:money="total = $event" />
<!-- .sync语法糖 <Child :money.sync="total" /> -->
</div>
</template>
<script>
import Child from "./Child.vue";
export default {
components: { Child: Child },
data() {
return { total: 10000 };
},
};
</script>
实现的原理是利用eventBus,在子组件使用$emit 来通知父组件去响应,而父组件则通过$event来接收经过子组件修改后的值。
注意事件名必须写为update:xxx,xxx是修改的属性名,也就是money
.sync可将
<Child :money="total" v-on:update:money="total = $event" />
简写为
<Child :money.sync="total" />
再解释一下$event
$event保存了通过事件抛出的值,父组件监听这个事件的时候就可以通过$event访问这个值,如果事件处理函数是一个方法,那么这个值会作为第一个参数传入方法,也就是说上面代码也可以写成
<Child :money="total" v-on:update:money="(restMoney) => total = restMoney" />