《.sync修饰符》

193 阅读1分钟

举个例子:

main.js

import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue 父组件

引入一个Child组件,Child需要外部给它传一个数据,money。于是App把它的total数据传给组件

<template>
  <div class="app">
    App.vue 我现在有 {{total}}
    <hr>
    <Child :money="total"/>
  </div>
</template>

<script>
import Child from "./Child.vue";
export default {
  data() {
    return { total: 10000 };
  },
  components: { Child }
};
</script>

<style>
.app {
  border: 3px solid red;
  padding: 10px;
}
</style>

Child.vue 子组件

需要一个外部数据money,由父组件App传入。有一个“花钱”按钮

<template>
  <div class="child">
    {{money}}
    <button>
      <span>花钱</span>
    </button>
  </div>
</template>

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

<style>
.child {
  border: 3px solid green;
}
</style>

类似于,儿子想花爸爸的钱。点击儿子身上的按钮,爸爸和儿子的钱会相应减少一定值。

所以应该怎么做呢?

想法1:直接在儿子身上花爸爸的钱

在Child.vue里:

<button @click="money-=100">
    <span>花钱</span>
</button>

会有警告,说不要直接修改外部属性,因为这个值当父组件重新渲染的时候会被父组件重写。

所以直接修改不行,因为你不能改外部属性,改了也没用

那怎么办呢?

想法2:想花钱,通知你爸爸不就好了

怎么通知? MVC里的eventBus。Vue内置了eventBus,而且this继承了eventBus类。

在Child.vue里:

<button @click="$emit('useMoney',money-100)">
    <span>花钱</span>
</button>

如果点击按钮,就使用$emit触发"useMoney" 事件,花100块钱,结果是money-100

在App.vue里:

<Child :money="total" @useMoney="total=$event"/>

使用Child组件时,先传total。监听useMoney事件,如果这个事件被触发了,就拿到$emit的结果值。这个结果值保存在$event变量里。

整个过程就是:爸爸给儿子一个money,儿子就看到了这个money。儿子想花钱的时候,就触发一个事件;爸爸监听了这个事件,当事件被触发时,就把儿子传过来的参数进行处理,而这个参数是存在$event上的。

最终效果儿子可以成功花钱,爸爸身上的钱会同步更新。

想法3:改进,最终写法

这里我们自己定义的事件名useMoney,Vue 规定了这个事件名:update:money

这是Vue里的一个很常见的场景。我给你一个数据,但是你要改的话,不能自己改。必须通知我,我去改。

每次监听都要写一大堆:传给你一个数据,监听事件,得到$event...

Vue把这些封装成了sync修饰符

在Child.vue里:

<button @click="$emit('update:money',money-100)">
    <span>花钱</span>
</button>

子组件里还是要使用 $emit 触发,要注意事件名是 update:...

在App.vue里:

<Child :money.sync="total" />

直接在给子组件的属性后边加 .sync ,就代替了想法2里的监听,取值等一长串代码。表示我给你一个money,你如果改了这个money,我就同步过来。

总结

Vue有以下规则:

  • 组件不能修改props外部数据
  • 使用 $emit 触发事件,并传参
  • $event 可以获取 $emit 的参数