本文提到三种组件之间通信的方式
-
父子组件之间通信
- props 和 $emit 适合直接父子关系的通信
- $attrs 和 $listeners 可以进行爷孙之间的通信
-
同级组件的通信
- *事件总线的方式
const EventBus = new Vue();
Vue.prototype.$EventBus = EventBus;
方式一:props和$emit
props以单向数据流的形式可以很好的完成父子组件的通信
- 所谓单向数据流,就是数据只能通过props由父组件流向子组件,而子组件并不能通过修改props传过的数据修改父组件的相应状态
<body>
<div id="app"></div>
<script src="node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
//父组件
Vue.component('parent',{
data(){
return{
message:'hello'
}
},
template:'<div>' +
'<p>this is parent component</p>' +
'<child :message="message" v-on:getChildData="getChildData"></child>' +
'</div>',
methods:{
getChildData(val){
console.log(val);
}
}
});
//子组件
Vue.component('child',{
template:'<div><input type="text" v-model="myMessage" @input="passData(myMessage)"/></div>',
prop:['message'],
data(){
return{
myMessage:this.message
}
},
methods:{
passData(val){
this.$emit('getChildData',val);
}
}
})
new Vue({
el:'#app',
template:'<div><parent/></div>'s
})
</script>
</body>
方式二:$attrs 和 $listeners
方式一组件通信的方式只适合直接的父子组件。针对方式一的不足,提供了attrs和listeners来实现直接让组件A传递消息给组件C
- 实现组件A传消息给组件C
<body>
<div id="app"></div>
<script src="node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
Vue.component('A',{
template: '<div><p>this is parent component</p><B :messagec="messagec" :message="message" ' +
'v-on:getCData="getCData(messagec)" v-on:getChildData="getChildData(message)"></B></div>',
data(){
return{
messagec:'hello c',
message:'hello'
}
},
methods:{
getChildData(val){
console.log('这是来自组件B的数据' + val)
},
getCData(val){
console.log('这是来自组件C的数据' + val)
}
}
});
//组件B
Vue.component('B',{
<!-- C组件中能直接触发 getCData 的原因在于:B组件调用 C组件时,使用 v-on 绑定了 $listeners 属性 -->
<!-- 通过v-bind 绑定 $attrs 属性,C组件可以直接获取到 A组件中传递下来的 props(除了 B组件中 props声明的) -->
template:'<div>' +
'<input type="text" v-model="mymessage" @input="passData(mymessage)">' +
'<C v-bind="$attrs" v-on="$listener"></C>' +
'</div>',
props:['message'],
data(){
return{
mymessage:this.message
}
},
methods:{
passData(val){
this.$emit('getChildData',val)
}
}
});
//组件C
Vue.component('C',{
template:'<div><input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"></div>',
methods:{
passCData(val){
//触发父组件A中的事件
this.$emit('getCData',val)
}
}
})
new Vue({
el:'#app',
template:'<div><A/></div>'
})
</script>
</body>
方式三:*事件总线EventBus(适用于同级组件)
对于父子组件之间的通信,上面两种方式可以完全实现,但是对于两个组件不是父子关系,又该如何实现呢?项目规模不大,可以使用*事件总线Event
<body>
<div id="app"></div>
<script src="vue.min.js"></script>
<script>
//EventBus 通过新建一个 Vue 事件 bus 对象,然后通过 bus.$emit 触发事件,bus.$on 监听触发的事件。
//定义*事件总线
const EventBus = new Vue();
//将*事件总线赋值到Vue.prototype上,这样所有组件都可以访问了
Vue.prototype.$EventBus = EventBus; //这里主要应该是在原型链上添加属性
//组件A
Vue.component('A',{
template:`
<div>
<p>this is A component</p>
<input type="text" v-model="mymessage" @input="passData(mymessage)" />
</div>
`,
data(){
return{
mymessage: 'hello brother1'
}
},
methods:{
passData(val){
this.$EventBus.$emit('globalEvent',val)
}
}
});
//组件B
Vue.component('B',{
template:`
<div>
<p>This is B component</p>
<p>组件A传过来的数据:{{brotherMessage}}</p>
</div>
`,
data(){
return{
brotherMessage:''
}
},
mounted(){
this.$EventBus.$on('globalEvent', (val) => {
this.brotherMessage = val;
})
}
})
new Vue({
el: '#app',
template:`
<div>
<A />
<B />
</div>
`
})
</script>
</body>
下篇想详细理解一下vuex再做个比较好的笔记,现在的笔记太乱啦~