Vue 组件间通信方式汇总,总有一款适合你( 附项目实战案例 )
前言
前期分享的 200行纯前端Vue代码!教你写一个专属TodoList【零基础友好】
这个项目案例中使用的组件间通信方式是通过 事件绑定
与props
接收来实现的,具体使用方式将在下面进行详细介绍,先说说这种方式来实现组件间的通信有什么缺点。
缺点:
以 200行纯前端Vue代码!教你写一个专属TodoList【零基础友好】
项目案例中的最外层组件 App.vue 的这段代码里的:checkTodo
事件来看。
因为 App.vue 组件的子组件 ListItem.vue 需要调用 App.vue 组件里封装好的checkTodo
方法,所以使用:checkTodo
进行事件绑定到子组件 AllList.vue 中。
然后再在 AllList.vue 组件中以同样的方式给其子组件 ListItem.vue 绑定事件进行传递,最终都使用props
进行绑定事件的接收,接收成功后才可在本组件中进行使用。
三个组件之间的关系如下图。
这种通信方式很明显的问题在于,传递过程太过冗长,麻烦了不该麻烦的人
。
本来 AllList.vue 组件不需要使用checkTodo
方法,但因为其子组件 ListItem.vue 要使用,所以不得不先接收由 App.vue 传递过来事件后再传递给其子组件 ListItem.vue,此时充当了中间人
的角色,相当于为父亲和儿子来传递消息
,且这个消息对自己并没有任何价值。
如果不选择这种通信方式,是否还有其他通信方式可以选择呢?
答案是:有的。而且你的选择可不只一种!
组件间通信方式
::: block-1
1. props
(1). 使用方法
需求背景
以上图中三个组件之间的关系为例,作为 AllList.vue 子组件的 ListItem.vue 组件想要获取 App.vue 组件的信息
使用步骤
Step1: 在 App.vue 组件中引入 AllList.vue 组件,在用该组件标签时,使用
:checkTodo
给其绑定事件。Step2: 回到 AllList.vue 组件中,使用
props
来接收checkTodo
,在用子组件 ListItem.vue 标签时,再使用:checkTodo
给其绑定事件。Step3: 回到 ListItem.vue 组件中,使用
props
来接收checkTodo
,接收后就可以在组件内部使用了。
(2). 实战代码案例
App.vue 组件核心内容
<template> <div class="todo-wrap"> <AllList :todos="todos":checkTodo="checkTodo"/> </div> </template>
<script> //引入子组件 import AllList from "./components/AllList" export default { //给当前组件命名为:App name:'App', //注册引入的子组件 components:{AllList}, //初始化的todo list数据 data(){ return { todos:[ {id:'001', title:'读文学书', done:true}, {id:'002', title:'解函数', done:false}, {id:'003', title:'上瑜珈课', done:false}, {id:'004', title:'研究三角函数', done:false}, ] } } } </script>
AllList.vue 组件核心内容
<template> <ul class="todo-main"> <!--给子组件ListItem绑定事件,例如:checkTodo,在ListItem组件中需要使用props进行声明接收后即可使用--> <ListItem :checkTodo="checkTodo"/> </ul> </template>
<script> //引入ListItem组件 import ListItem from "./ListItem" export default { //给组件命名为: AllList name:'AllList', //在当前组件内注册子组件: ListItem components:{ListItem}, //props用于接收App组件传递过来的参数 props:['checkTodo'] } </script>
ListItem.vue 组件核心内容
<template> <li> <label> <!-- 1.初始化时: 绑定checked事件,如果为true时则勾选中checkbox,反之不勾选中checkbox 2.数据变更时: 绑定change事件,调用handleCheck方法并传入当前item的所属id值来操作是取消还是选中checkbox的勾选 --> <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/> <span>{{todo.title}}</span> </label> </li> </template>
<script> export default{ //给当前组件命名为: ListItem name:'ListItem', //使用props声明接收父组件AllList里checkTodo props:['checkTodo'], methods: { //勾选or取消勾选 handleCheck(id) { //通知App组件将对应的todo对象的done值取反 this.checkTodo(id) } } } </script>
:::
::: block-1
2. 全局事件总线
(1). 使用方法
需求背景
A 组件想要接收 B 组件传递的数据
使用步骤
Step1: 在入口
main.js
文件中安装全局事件总线。安装位置为:在创建 vue 实例对象时传入的配置项里调用
beforeCreate
钩子函数配置。Step2: B 组件在
mounted
函数中使用this.$bus.$on('deleteTodo',callback)
进行事件绑定,事件名称为:deleteTodo。Step3: A 组件中使用
this.$bus.$emit('deleteTodo',id)
进行全局事件总线的触发,这里触发的事件名与 B 组件绑定的事件名一致。
(2). 实战代码案例
背景
上面的 todoList 项目案例中,不想使用 AllList.vue 组件作为中间人来传递消息,想直接使用
全局事件总线
的方式来实现 App.vue 与 ListItem.vue 的通信。在 main.js 入口文件中安装全局事件总线
main.js 文件内容
//引入Vue import Vue from 'vue' //引入App import App from './App.vue' //关闭Vue的生产提示 Vue.config.productionTip = false //创建vm new Vue({ el:'#app', render: h => h(App), beforeCreate() { Vue.prototype.$bus = this //安装全局事件总线 } })
App.vue 组件核心内容
mounted() { // 绑定全局事件总线,事件名称:delteTodo this.$bus.$on('deleteTodo',this.deleteTodo) }, beforeDestroy() { // 销毁事件名称为:deleteTodo 的全局事件总线 this.$bus.off('deleteTodo') }
ListItem.vue 组件核心内容
methods: { //删除 handleDelete(id){ if(confirm('确认删除吗?')){ //通过$emit来触发App.vue组件绑定的全局事件总线,事件名称:deleteTodo,来通知App组件将对应的todo对象删除掉 this.$bus.$emit('deleteTodo',id) } } }
:::
::: block-1
3. 消息订阅与发布
(1). 使用方法
需求背景
A 组件想要接收 B 组件传递的数据
使用步骤
Step1: 在 B 组件中进行消息发布,发布消息的名称为:sendMsg
Step2: A 组件对 B 组件发布的消息进行订阅,订阅消息的名称是:sendMsg
Step3: A 组件需要在钩子函数
beforeDestroy
中取消订阅 (规范流程要求)
(2). 实战代码案例
背景
现有 City.vue 和 Province.vue 两个组件,City.vue 组件想把数据传递给组件 Province.vue 组件。
City.vue 组件内容
<script> import pubsub from 'pubsub-js' export default { name:'City', data() { return { name: '武汉' } }, methods:{ sendCityName(){ pubsub.publish('receiveName',this.name) } } } </script>
Province.vue 组件内容
<script> import pubsub from 'pubsub-js' export default { name:'Province', data(){ return { ProvinceName: '湖北', cityName: '' } }, methods: { // 对收到的订阅消息进行处理,替换已有的cityName的值 getCityName(msgName,data){ this.cityName = data } }, mounted() { // 这里订阅消息的名称receiveName要与City.vue组件中发布消息的名称保持一致,这样才能接受到订阅的消息 this.pubId = pubsub.subscribe('receiveName',this.getCityName) }, beforeDestroy() { // 在销毁之前取消订阅 pubsub.unsubscribe(this.pubId) } } </script>
:::
小结
今天的分享详细地介绍了在 Vue 中常见的三种组件间的通信方式,分别是:
- props
- 全局事件总线
- 消息订阅与发布
这三种组件间通信方式的使用方法以及对应的实战案例都有详细地说明,强烈建议动手练起来。
适用于测试开发,后端开发,前端开发。
有基础的同学可以自己写个小 demo 把这三种通信方式都运用起来,没基础的同学可以在公众号后台回复:todo,拿到我之前写好的 todoList 案例直接进行修改也是可以的。
因为篇幅有限,将在后续的文章中继续为大家分享 Vue 中其他的组件间通信方式,例如:slot(插操),Vuex 等通信方式。相信总有一款适合你!