Vue中,不同组件之间通信,有哪些方式?
约 1637 字大约 5 分钟
2025-03-14
1. prop 属性 父传子
通过 prop 属性,可以实现父组件向子组件传递信息
父组件
<template>
<div>
<!-- 传递值 -->
<Test :obj="obj" info="测试" />
</div>
</template>
<script>
import Test from "../components/Test.vue"; // 引入子组件
export default {
name: "about",
components: { Test }, // 注册子组件
data() {
return {
obj: {
code: 200,
title: "父组件传值title",
},
};
},
};
</script>
子组件
<template>
<div>
<h1>{{ obj.code }}</h1>
<br />
<h2>{{ obj.title }}</h2>
<h3>{{ info }}</h3>
</div>
</template>
<script>
export default {
name: "test",
props: {
obj: Object,
info: [String, Number], //info值为其中一种类型即可,其他类型报警告
},
};
</script>
2. $emit 事件 子传父
通过 $emit,可以实现子组件向父组件传递信息
父组件
<template>
<div><Test @return="loadData" /><!-- 传递值 --></div>
</template>
<script>
import Test from "../components/Test.vue"; // 引入子组件
export default {
name: "about",
components: { Test }, // 注册子组件
methods: {
loadData(param) {
console.log(param); // '子组件传递过来的值'
},
},
};
</script>
子组件
<script>
export default {
name: "Test",
created() {
this.$emit("return", "子组件传递过来的值");
},
};
</script>
3. v-model 值绑定 双向获取
v-model
为双向传值,主要是通过两方面:prop 和$emit 来实现
父组件
<!-- xxData和子组件里的customValue的属性值可以不一样 -->
<Test v-model="xxData" info="测试" />
子组件
<script>
export default {
name: "Test",
props: ["customValue"],
model: {
prop: "customValue",
event: "update",
},
created() {
this.$emit("update", newCustomValue); // 当值发生变化时,抛出事件触发更新
},
};
</script>
4. $refs 父获取子
通过该属性可以获取已经标记ref='xxx'
的子组件,通过this.$refs.xxx
来访问对应的属性和方法。
5. $children 父获取子
可以通过该属性获取子组件的集合(列表),根据下标 index 来获取想操作的子组件。
this.$children[index].xxxx;
6. $parent 子获取父
通过该属性可以访问父组件的属性和方法
this.$parent.getQuery();
this.$parent.xxxxx;
7. provide
和 inject
隔代注入 父传子 Vue3
实现父组件向子孙孙组件传值。(层级不限,跨越层级),父组件通过provide
提供信息,后代组件通过inject
注入该信息。
父组件
export default {
name: "father",
provide() {
// 使用函数return主要是为了确保数据响应性 和组件解耦
return {
titleFather: "父组件的值",
};
},
};
子/孙组件
export default {
name: "sonone",
inject: ["titleFather"],
created() {
console.log(this.titleFather); // 父组件的值
},
};
8. $attrs 父传子
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
9. $listeners 父传子
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
10. EventBus 事件总线 随便传
需要考虑组件加载的生命周期,缺点就是代码变复杂,维护困难
$emit
抛出事件,发送数据。 通常放在mounted
或用户交互的回调函数
中
$on
检测到对应事件,接收数据。通常放在mounted
钩子中
$off
页面销毁前,需要及时清理监听,否则会造成内存泄漏。通常放在beforeDestroy
钩子中解绑事件
发送数据
// ComponentB.vue
export default {
methods: {
sendData() {
this.$bus.$emit("xxx", { name: "Vue", version: "3.x" });
},
},
};
接受数据数据
// ComponentA.vue
export default {
mounted() {
this.$bus.$on("xxx", this.demo);
},
methods: {
demo(data) {
console.log(data); // 处理接收到的数据
},
},
beforeDestroy() {
this.$bus.$off("xxx"); // 组件销毁前解绑事件
},
};
11. Vuex 随便传
State 仓库
State 就是 store 仓库,用来存放取数据。mapState 是为了简化代码,一次性获取多个 store 里的数据
// 获取单个数据
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
computed: {
count() {
return this.$store.state.count;
},
},
};
</script>
// 映射多个数据
<script>
import { mapState } from 'vuex'
export default {
computed: mapState({
count: state => state.count,// 箭头函数可使代码更简练
countAlias: 'count',// 字符串参数'count' 等同于 `state => state.count`
countPlusLocalState (state) {
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
return state.count + this.localCount
}
})
// 如果不需要别名,可以用数组形式
computed: mapState([
'count'// 映射 this.count 为 store.state.count
])
}
</script>
Getter 获取数据,加工数据
Getter 是相当于对 state 里的数据的一个加工处理,拿到的返回值就是处理后的值,但不允许在 getter 里取改变 store 里的值。
Mutation 突变 数据刷新
Mutation 是同步执行的,不能出现异步任务,比如 promise。触发 Mutation 后,store 里的值会立即刷新。Moutation 的变化是可以被 devtool 追踪到的。
你可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 和 mutation 关联(需要在根节点注入 store)。
Action 动作 方法
Action 支持异步任务,相当于为了弥补 Mutation 不能执行异步任务的遗憾,使其搭配异步任务完成某一个 Action。同时 Action 也是相当于把某些高频出现的包含业务逻辑的 methods 提取出来,作为一个公共的 Aciton 使用。
可以在组件中使用this.$store.dispatch('xxx')
分发 action,或者使用 mapActions 辅助函数将组件的 methods 关联到 Action 调用(需要先在根节点注入 store):
this.$store.dispatch("products/getAllProducts", xxxxx);
Modules 模块
项目比较大,逻辑比较复杂的时候,sotre、action、mutation 等相关代码会变得非常庞大。进行模块拆分,有利于提高代码的维护性和可靠性
与表单的有机结合
如果我们直接把 vuex 里的值绑定到的表单的v-model上。因为v-model是双向刷新的,而 vuex 不允许直接修改值来刷新。所以我们需要使用另外一个变量,设置为计算属性(computed)。通过该属性的get方法来取出 vuex 里存储的对应值,通过set来提交Mutation刷新 Vuex 里的值。如果需要设置该值的初始值,可以初始化的时候赋初始值。
<input v-model="message">
// -------
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
更新日志
e7112
-1于