兄弟组件数据共享(event bus事件总线)
作用:非父子组件之间进行简易消息传递
EventBus的使用步骤:
① 创建 eventBus.js 模块,并向外共享一个 Vue的实例对象
② 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件
③ 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件
utils/EventBus.js
import Vue from "vue";
const bus = new Vue()
export default bus
components/MySon1.vue
<template>
<div>
<div class="header">
MySon1数据发送方
<button @click="sendFn">发送数据</button>
</div>
</div>
</template>
<script>
import Bus from '@/utils/EventBus'
export default {
data() {
return {
msg: '你好',
}
},
methods: {
sendFn() {
Bus.$emit('sendMsg', this.msg)
}
},
}
</script>
<style scoped lang="less">
.header {
width: 300px;
height: 300px;
background-color: pink;
border-radius: 5px;
margin-bottom: 10px;
text-align: center;
.tit {
font-size: 22px;
}
}
</style>
components/MySon2.vue
<template>
<div>
<div class="main">
MySon2数据接收方---{{ msgfromSon }}
</div>
</div>
</template>
<script>
import Bus from '@/utils/EventBus'
export default {
data() {
return {
msgfromSon: '',
}
},
created() {
Bus.$on('sendMsg', (msg) => {
this.msgfromSon = msg
})
}
}
</script>
<style scoped lang="less">
.main {
width: 300px;
height: 300px;
background-color: blueviolet;
border-radius: 5px;
margin-bottom: 10px;
.tit {
text-align: center;
font-size: 22px;
}
ul {
li {
text-align: left;
span {
float: left;
}
}
}
}
</style>
App.vue
<template>
<div id="app">
<MySon1></MySon1>
<MySon2></MySon2>
</div>
</template>
<script>
import MySon1 from '@/components/MySon1.vue'
import MySon2 from '@/components/MySon2.vue'
export default {
components: {
MySon1,
MySon2,
},
data() {
return {
}
},
}
</script>
<style scoped lang="less">
#app {
width: 800px;
margin: 0 auto;
background-color: #ccc;
}
</style>
Provide 和 Inject---跨层级共享数据
基本使用
Provide / Inject 用于非父子组件之间跨层级共享数据:
- 比如有一些深度嵌套的组件,子组件想要获取父组件的部分内容;
- 在这种情况下,如果我们仍然将props沿着组件链逐级传递下去,就会非常的麻烦;
对于这种情况下,我们可以使用 Provide 和 Inject :
- 无论层级结构有多深,父组件都可以作为其所有子组件的依赖提供者;
- 父组件有一个 provide 选项来提供数据;
- 子组件有一个 inject 选项来开始使用这些数据;
实际上,你可以将依赖注入看作是“long range props”,除了:
- 父组件不需要知道哪些子组件使用它 provide 的 property
- 子组件不需要知道 inject 的 property 来自哪里
我们开发一个下面这样的结构: 让App.vue提供一些数据给HomeContent.vue使用
1. 祖先组件通过provide将数据传出, provide对应的是一个对象
export default {
components: {
Home
},
// 通过provide将数据传出
provide() {
return {
color: this.color, // 简单类型(非响应式数据)
name: this.name,
age: this.age,
height: this.height
userInfo: this.userInfo, // 复杂类型 响应式--推荐
}
}
}
在后代元素中, 通过inject接收祖先传递的数据, inject对应的是一个数组
export default {
inject: ["color", "name", "age", "height", "userInfo"]
}
处理响应式数据(了解)
我们先来验证一个结果:如果我们修改了this.name的内容,那么使用length的子组件会不会是响应式的?
<template>
<div class="app">
<home />
<h2>{{ name }}</h2>
<button @click="btnClick">按钮</button>
</div>
</template>
<script>
import Home from './Home.vue'
export default {
components: {
Home
},
data() {
return {
name: "chenyq",
age: 18,
height: 1.88,
}
},
// 通过provide将数据传出
provide() {
return {
name: this.name,
age: this.age,
height: this.height
}
},
methods: {
btnClick() {
this.name = "kaisa"
}
},
}
</script>
我们会发现对应的子组件中是没有反应的:
这是因为当我们修改了name之后,之前在provide中引入的 this.name 本身并不是响应式的;
那么怎么样可以让我们的数据变成响应式的呢?
- 非常的简单,我们可以使用响应式的一些API来完成这些功能,比如说computed函数;
- 当然,这个computed是vue3的新特性,在后面我会专门讲解,这里大家可以先直接使用一下;
import { computed } from 'vue'
export default {
components: {
Home
},
data() {
return {
name: "chenyq",
age: 18,
height: 1.88,
}
},
// 通过provide将数据传出
provide() {
return {
name: computed(() => this.name),
age: this.age,
height: this.name
}
},
methods: {
btnClick() {
this.name = "kaisa"
}
},
}
注意:我们在使用name的时候需要获取其中的value
- 这是因为computed返回的是一个ref对象,需要取出其中的value来使用;
<template>
<div class="home-content">
<h2>名字: {{ name.value }}, 年龄: {{ age}}, 身高: {{ height}}</h2>
</div>
</template>