Vue中 .sync修饰符

280 阅读1分钟

一、$emit

子组件通过props可以引用父组件的数据,那么当子组件想要修改这个数据时,则可以通过$emit在子组件上修改父组件的数据。

$emit 共接收两个参数 :

  • {string} eventName 触发当前实例上的事件。
  • [...args] 附加参数都会传给监听器回调。

示例

情景:爸爸给儿子钱,儿子要花钱,儿子可以看到具体的钱是多少,但是儿子要花钱不能直接花,需要通过触发一个事件,爸爸监听这个事件,爸爸通过$event接受儿子传递过来的参数

  • 子组件可以通过调用$emit传入事件名称来触发一个事件:
 //child.vue
<template>
    <div class="child">
      爸爸有{{money}}
       <button @click="$emit('update:money', money - 10)">我要花钱</button>
    </div>
</template>
  
<script>
  export default {
    props: ["money"]
  }
</script>
  
<style>
      .child{
          border:1px solid green;
      }
      
</style>
复制代码
  • 父组件的子组件器上使用v-on监听这个自定义事件,通过$event接受子组件传递过来的参数
//parent.vue
<template>
  <div class="parent">
    <div>
      爸爸现在有{{ total }}元钱
      <hr/>
      <Child :money="total" v-on:update:money="total = $event"/>
        // :money="total"的意思是 money 这个外部值传入的是 total 这个变量,传变量需要前面加:
    </div>
  </div>
</template>

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

<style>
    .parent{
        border:1px solid red;
    }
</style>
复制代码

二、.sync

.sync简化了上述代码,直接在父组件上使用

//parent.vue
<template>
  <div class="parent">
    <div>
      爸爸现在有{{ total }}元钱
      <hr/>
      <Child :money.sync="total"/>
    </div>
  </div>
</template>
复制代码

:money.sync="total" 等价于:money="total" v-on:update:money="total = $event"

三、案例

<div id="app">
    <div>{{bar}}</div>
    <my-comp :foo.sync="bar"></my-comp>
    <!-- <my-comp :foo="bar" @update:foo="val => bar = val"></my-comp> -->
</div>
<script>
    Vue.component('my-comp', {
        template: '<div @click="increment">点我+1</div>',
        data: function() {
            return {copyFoo: this.foo}
        },
        props: ['foo'],
        methods: {
            increment: function() {
                this.$emit('update:foo', ++this.copyFoo);
            }
        }
    });
    new Vue({
        el: '#app',
        data: {bar: 0}
    });
</script>

说明: 代码会被扩展成<comp :foo="bar" @update:foo="val => bar = val">,就是一个语法糖。

四、总结

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

从 2.3.0 起我们重新引入了 .sync 修饰符,但是这次它只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。
示例代码如下:

**

<comp :foo.sync="bar"></comp>

会被扩展为:

**

<comp :foo="bar" @update:foo="val => bar = val"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

**

this.$emit('update:foo', newValue)

猛一看不明白,下边我么通过一个实例(弹窗的关闭事件)来说明这个代码到底是怎么运用的。

**

<template>
    <div class="details">
        <myComponent :show.sync='valueChild' style="padding: 30px 20px 30px 5px;border:1px solid #ddd;margin-bottom: 10px;"></myComponent>
        <button @click="changeValue">toggle</button>
    </div>
</template>
<script>
import Vue from 'vue'
Vue.component('myComponent', {
      template: `<div v-if="show">
                    <p>默认初始值是{{show}},所以是显示的</p>
                    <button @click.stop="closeDiv">关闭</button>
                 </div>`,
      props:['show'],
      methods: {
        closeDiv() {
          this.$emit('update:show', false); //触发 input 事件,并传入新值
        }
      }
})
export default{
    data(){
        return{
            valueChild:true,
        }
    },
    methods:{
        changeValue(){
            this.valueChild = !this.valueChild
        }
    }
}
</script>

效果如下:

image.png

vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的那个弹窗功能,我们也可以props传初始值,然后事件监听,实现起来也不算复杂。这里用sync实现,只是给大家提供一个思路,让其明白他的实现原理,可能有其它复杂的功能适用sync。



链接:www.jianshu.com/p/6b062af8c…

作者链接:juejin.cn/post/699285…