在使用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 在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。