对于使用Vue的新手来说,组件之间的数据传递是一个比较麻烦的问题,在开发中我自己也踩了不少坑,这篇文章简单地做了一个总结。
首先,在 Vue 中,父子组件的关系可以总结为 props down, events up。父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息。如下图:
目录
- 1. 父子组件之间的数据传递
- 1.1 父组件向子组件传递数据
- 1.2 子组件向父组件传递事件
- 2. 非父子关系组件之间的数据传递
父子组件之间的数据传递
父组件向子组件传递数据
组件实例的作用域(scope)是孤立的,所以组件之间无法相互访问到对方的数据,所以这里我们需要在子组件中使用props
选项去接受来自父组件传递进来的动态数据,并且在父组件的标签上绑定v-bind该数据,这样一来,我们就把父组件中的数据传递给了子组件中。
// 创建父组件
Vue.component("m-super", {
data: ()=>{
return {
message: "Hello Super"
}
},
template: `<div>
<input placeholder='请输入message的值' v-model='message'></input>
<br/>
<m-child :message='message'></m-child>
</div>`
});
// 创建子组件,并需要把父组件的message的值传递给子组件
Vue.component("m-child", {
props: ["message"],
template: "<span>子组件显示:{{ message }}</span>"
})
props
数据是单向传递
props
是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。
这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。
每次父组件更新时,子组件的所有 prop 都会更新为最新值。这意味着你不应该在子组件内部改变 prop。如果你这么做了,Vue 会在控制台报错。如下:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "message"
子组件向父组件传递事件
因为prop
是单向数据流的,所以prop接受的数据是无法双向绑定的,那么如何改变父组件的数据呢——使用vue
的自定义事件。
- 子组件中我们可以通过$emit(eventName)来触发事件
- 父组件中我们可以通过$on(eventName)来监听事件
下面给子组件添加了一个重置按钮,一按就可以将父组件的值改为Hello Child
。代码如下:
// 创建父组件
Vue.component("m-super", {
data: ()=>{
return {
message: "Hello Super"
}
},
template: `<div>
<input placeholder='请输入message的值' v-model='message'></input>
<br/>
<m-child :message='message' v-on:reset="reset"></m-child>
</div>`,
methods:{
reset:function(e){
this.message = e
}
}
});
// 创建子组件,并需要把父组件的message的值传递给子组件
Vue.component("m-child", {
props: ["message"],
template: "<div><span>子组件显示:{{ message }}</span><br/><button v-on:click='reset()'>重置</button></div>",
methods: {
reset:function(){
this.$emit("reset", "Hello child")
}
}
})
这样一来,我们便实现了父子组件数据的双向绑定。
非父子组件之间的数据传递
对于非父子组件通信情况,在简单的场景下,可以使用一个空的Vue
实例作为中央事件总线:
var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})
如果非父子组件通信比较复杂时,我们可以通过Vuex来解决。