组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。一般来说,组件可以有以下j几种关系:
如上图所示,A和B、B和C、B和D都是父子关系,C和D是兄弟关系,A和C是隔代关系(可能隔多代)。
针对不同的使用场景,如何选择行之有效的通信方式,这是我们所要探讨的主题。本文总结了vue组件间通信的几种方式,如props、$emit / $on、vuex、$parent / $children、$attrs / $listeners 和provide/inject,以通俗易懂的实例讲述这其中的差别及使用场景,希望对小伙伴有些许帮助。
方法一、props / $emit
父组件A通过props的方式向子组件B传递,B to A通过在B组件中$emit,A组件中v-on的方式实现。
1.父组件向子组件传值
接下来我们通过一个例子,说明父组件如何向子组件传递值:在子组件Users.vue中如何获取父组件App.vue中的数据users:["henrry","Bucky","Emily"]
总结:父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed
2. 子组件向父组件传值(通过事件形式)
接下来我们通过一个例子,说明子组件如何向父组件传递值:当我们点击“Vue,js Demo”后,子组件向父组件传递值,文字由原来的“传递的是一个值”变成“子向父组件传值”,实现子组件向父组件值的传递。
总结:子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
方法二、$emit / $on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件和监听事件,巧妙而轻量地实现了任何组件之间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好地状态管理解决方案vuex。
1. 具体实现方式:
2. 举个例子
假设兄弟组件有三个,分别是A、B、C组件,C组件如何获取A或者B组件的数据
$on监听了自定义事件data-a和data-b,因为有时不确定何时会触发事件,一般会在mounted或created钩子中来监听
方法三、vuex
1. 简单介绍Vuex原理
Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
2. 简要介绍各模块在流程中的功能:
Vue Components: Vue 组件。HTML页面上, 负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
dispatch: 操作行为触发方法,是唯一能执行action的方法。
actions:操作行为处理模块,由组件中的$store.dispatch('action 名称',data1)来触发,然后由commit()来触发mutation的调用,简介更新state。负责处理Vue Components接收到所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发,向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以及支持action的链式触发。
commmit:状态改变操作方法,由actions中的commit (‘mutation 名称’)来触发。是Vues修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
state: 页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
getters: state对象读取方法。图中没有单独列出该模块,应该被包含在了render中,Vue Components通过该方法读取全局state对象。
3. Vuex 与 localStorage
vuex是vue的状态管理器,存储数据是响应式的。但是并不会保存起来,刷新之后就会回到了初始状态,具体的做法应该是在vuex里的数据改变的时候把数据拷贝一份保存到localStorage里边,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。
这里需要注意的是:由于vuex里,我们保存的状态都是数据,而localStorage只支持字符串,所以需要用JSON转换:
4. $parent / $children & ref
ref: 如果在普通的DOM元素上使用,引用指向的就是Dom元素;如果用在子组件上,引用就指向组件实例
$parent / $children: 访问父 、子实例
需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。我们先来看个用ref来访问组件的例子:
不过,这两种方法的弊端是无法在跨级或兄弟组件之间通信。
饿哦们想在component-a中,访问到引用它的页面中(这里就是parent.vue)的两个component-b组件,那这种情况下,就得配置额外的插件或工具了,比如Vuex和Bus的解决方案。