目录
一、引言
1.1. event bus 事件总线
1.1.1. 实现步骤
1.2. provide & inject
1.2.1. 实现步骤
二、event bus事件总线完整代码
2.1. 工程结构图
2.2. main.js
2.3. App.vue
2.4. EventBus.js
2.5. BaseC.vue
2.6. BaseB.vue
2.7. BaseA.vue
三、provide & inject
3.1. 工程结构图
3.2. main.js
3.3. App.vue
3.4. GrandSon.vue
3.5. SonA.vue
3.6. SonB.vue
一、引言
前面几个章节我们重点讲解了在Vue中组件的关系类别及父子组件的通信解决方案,本章内容将详细讲解关于非父子组件间的通信解决方案。那么非父子组件的通信我们分为两种:
1.1. event bus 事件总线
作用:非父子组件之间,进行简易消息传递。(复杂场景 → Vuex)
1.1.1. 实现步骤
1. 创建一个都能访问到的事件总线 (空 Vue 实例) → 在utils包下创建EventBus.js
2. A 组件(接收方),监听 Bus 实例的事件
3. B 组件(发送方),触发 Bus 实例的事件
1.2. provide & inject
作用:跨层级共享数据
注:在使用跨层级进行父组件和子孙组件进行共享数据时,能够进行简单数据类型(非响应式)及复杂数据类型(响应式)的共享,但是实际使用过程中,我们建议使用复杂类型来做数据共享,因为该类型的数据是响应式的,因此其他组件在获取使用时能够直接生效。
1.2.1. 实现步骤
1. 父组件 provide 提供数据
2. 子/孙组件 inject 取值使用
二、event bus事件总线完整代码
2.1. 工程结构图
2.2. main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
2.3. App.vue
<template>
<div class="app">
<BaseA></BaseA>
<BaseB></BaseB>
<BaseC></BaseC>
</div>
</template>
<script>
import BaseA from './components/BaseA.vue'
import BaseB from './components/BaseB.vue'
import BaseC from './components/BaseC.vue'
export default {
components:{
BaseA,
BaseB,
BaseC
}
}
</script>
<style>
</style>
2.4. EventBus.js
import Vue from 'vue'
const Bus = new Vue()
export default Bus
2.5. BaseC.vue
<template>
<div class="base-c">
我是C组件(接受方)
<p>{{msg}}</p>
</div>
</template>
<script>
import Bus from '../utils/EventBus'
export default {
data() {
return {
msg: '',
}
},
created() {
Bus.$on('sendMsg', (msg) => {
// console.log(msg)
this.msg = msg
})
},
}
</script>
<style scoped>
.base-c {
width: 200px;
height: 200px;
border: 3px solid #000;
border-radius: 3px;
margin: 10px;
}
</style>
2.6. BaseB.vue
<template>
<div class="base-b">
<div>我是B组件(发布方)</div>
<button @click="sendMsgFn">发送消息</button>
</div>
</template>
<script>
import Bus from '../utils/EventBus'
export default {
methods: {
sendMsgFn() {
Bus.$emit('sendMsg', '今天天气不错,适合旅游')
},
},
}
</script>
<style scoped>
.base-b {
width: 200px;
height: 200px;
border: 3px solid #000;
border-radius: 3px;
margin: 10px;
}
</style>
2.7. BaseA.vue
<template>
<div class="base-a">
我是A组件(接受方)
<p>{{msg}}</p>
</div>
</template>
<script>
import Bus from '../utils/EventBus'
export default {
data() {
return {
msg: '',
}
},
created() {
Bus.$on('sendMsg', (msg) => {
// console.log(msg)
this.msg = msg
})
},
}
</script>
<style scoped>
.base-a {
width: 200px;
height: 200px;
border: 3px solid #000;
border-radius: 3px;
margin: 10px;
}
</style>
三、provide & inject
3.1. 工程结构图
3.2. main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
3.3. App.vue
<template>
<div class="app">
我是APP组件
<button @click="change">修改数据</button>
<SonA></SonA>
<SonB></SonB>
</div>
</template>
<script>
import SonA from './components/SonA.vue'
import SonB from './components/SonB.vue'
export default {
provide() {
return {
// 简单类型 是非响应式的
color: this.color,
// 复杂类型 是响应式的
userInfo: this.userInfo,
}
},
data() {
return {
color: 'pink',
userInfo: {
name: 'zs',
age: 18,
},
}
},
methods: {
change() {
this.color = 'red'
this.userInfo.name = 'ls'
},
},
components: {
SonA,
SonB,
},
}
</script>
<style>
.app {
border: 3px solid #000;
border-radius: 6px;
margin: 10px;
}
</style>
3.4. GrandSon.vue
<template>
<div class="grandSon">
我是GrandSon
{{ color }} -{{ userInfo.name }} -{{ userInfo.age }}
</div>
</template>
<script>
export default {
inject: ['color', 'userInfo'],
}
</script>
<style>
.grandSon {
border: 3px solid #000;
border-radius: 6px;
margin: 10px;
height: 100px;
}
</style>
3.5. SonA.vue
<template>
<div class="SonA">我是SonA组件
<GrandSon></GrandSon>
</div>
</template>
<script>
import GrandSon from '../components/GrandSon.vue'
export default {
components:{
GrandSon
}
}
</script>
<style>
.SonA {
border: 3px solid #000;
border-radius: 6px;
margin: 10px;
height: 200px;
}
</style>
3.6. SonB.vue
<template>
<div class="SonB">
我是SonB组件
</div>
</template>
<script>
export default {
}
</script>
<style>
.SonB {
border: 3px solid #000;
border-radius: 6px;
margin: 10px;
height: 200px;
}
</style>