谈谈sync修饰符

403 阅读1分钟

在使用Vue的过程中,我们常常用到组件,在一个Vue实例上调用一个组件时,我们可以把实例中的数据通过绑定的方式传入到组件中,如果在实例中修改这个数据,毫无疑问组件中的该数据也会相应修改,如果只是简单地在组件中修改传入的值,那么Vue会给出警告不建议那样做,因为一旦实例中的数据有了变化,组件也会相应变化,但是有时候我们也需要在组件中修改这个数据,同时希望能将该数据的变化对应到实例中去,应该怎么做呢?

很简单,我们可以在实例中监听一个自定义事件,然后当组件修改了数据之后就触发这个事件,并将要修改的值传入到事件中,而实例就对应接收该值并同步修改自己的数据,也就是使用 $emit 函数,示例如下:

定义一个名为 Mycomponent 的全局组件,组件的模板内显示一个外部传入的数据 show 和一个 button,点击 button 时触发一个自定义的名为 "update:value" 的事件,并传入一个值 "child",在Vue实例中调用该组件,并将自己的数据 parent 绑定在 show 中传入到组件里,同时监听一个自定义事件 "update:value",如果事件触发,就在触发时将自己的数据 parent 修改为传入的值:(代码中使用的是vue的完整版)

Vue.component("Mycomponent", {
  template: `
     <div>
     组件中:<strong>{{show}}</strong>
     <button @click='$emit("update:show","child")'>modify</button>
     </div>
     `,
  props: ["show"]
});

new Vue({
  template: `
   <div>
       实例中:<strong>{{parent}}</strong>
        <Mycomponent :show=parent @update:show='modify'></Mycomponent> 
       </div>
   `,
   methods:{
     modify(value){
       this.parent=value
     }
   },
  data: {
    parent: "fu"
  }
}).$mount("#app");

在Vue中,可以直接使用 $event 来访问到组件使用 $emit 函数时传入的值,因此上述代码可以这样写:

Vue.component("Mycomponent", {
  template: `
     <div>
     组件中:<strong>{{show}}</strong>
     <button @click='$emit("update:show","child")'>modify</button>
     </div>
     `,
  props: ["show"]
});

new Vue({
  template: `
   <div>
       实例中:<strong>{{parent}}</strong>
        <Mycomponent :show=parent @update:show='parent=$event'></Mycomponent> 
       </div>
   `,
  data: {
    parent: "fu"
  }
}).$mount("#app");

说了这么多,sync 修饰符是干什么的呢?其实 sync 就是一种语法糖,为了方便起见对上面那种模式的缩写,如果使用 sync ,我们就可以不用在实例中写事件监听了,将 sync 放在传参的地方,可以直接写成如下形式:

Vue.component("Mycomponent", {
  template: `
     <div>
     组件中:<strong>{{show}}</strong>
     <button @click='$emit("update:show","child")'>modify</button>
     </div>
     `,
  props: ["show"]
});

new Vue({
  template: `
   <div>
       实例中:<strong>{{parent}}</strong>
        <Mycomponent :show.sync=parent></Mycomponent> 
       </div>
   `,
  data: {
    parent: "fu"
  }
}).$mount("#app");

使用 sync 需要注意的地方:

  • 必须以 update:myPropName 的模式触发事件
  • .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:show="parent+'!'" 是无效的),只能提供你想要绑定的 property 名
  • 将 v-bind.sync 用在一个字面量的对象上,例如 v-bind.sync="{ parent: parent}" 是无法正常工作的,因为 Vue 在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。