Vuex实现了一个单项数据流,通过创建一个全局的 State 数据,组件想要修改 State 数据只能通过 Mutation 来进行,例如页面上的操作想要修改 State 数据时,需要通过 Dispatch (触发 Action ),而 Action 也不能直接操作数据,还需要通过 Mutation 来修改 State 中数据,最后根据 State 中数据的变化,来渲染页面。
// index.js
import Vue from 'vue';
import Tpl from './index.vue';
import store from './store';
new Vue({
store,
render: h => h(Tpl),
}).$mount('#app');
// store
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment(state) {
state.count++;
},
reduce(state) {
state.count--;
}
},
actions: {
actIncrement({ commit }) {
commit('increment');
},
actReduce({ commit }) {
commit('reduce');
}
},
getters: {
doubleCount: state => state.count*2
}
});
export default store;
背景
初识 Vue.js ,了解到组件是 Vue 的主要构成部分,但组件内部的作用域是相对独立的部分,组件之间的关系一般如下图:
组件 A 与组件 B 、C 之间是父子组件,组件 B 、C 之间是兄弟组件,而组件 A 、D 之间是隔代的关系。
那么对于这些不同的关系,本文主要分享了他们之间可以采用的几种数据通信方式,例如 Props 、\$emit / \$on 、Vuex 等,大家可以根据自己的使用场景可以选择适合的使用方式。
一、 Prop / \$emit
1、Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 Prop 特性的时候,它就变成了那个组件实例的一个属性。父组件向子组件传值,通过绑定属性来向子组件传入数据,子组件通过 Props 属性获取对应数据
2、\$emit 子组件向父组件传值(通过事件形式),子组件通过 $emit 事件向父组件发送消息,将自己的数据传递给父组件。
小总结:常用的数据传输方式,父子间传递。
二、 \$emit / \$on
这个方法是通过创建了一个空的 vue 实例,当做 \$emit 事件的处理中心(事件总线),通过他来触发以及监听事件,方便的实现了任意组件间的通信,包含父子,兄弟,隔代组件。
小总结:巧妙的在父子,兄弟,隔代组件中都可以互相数据通信。
三、 Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex实现了一个单项数据流,通过创建一个全局的 State 数据,组件想要修改 State 数据只能通过 Mutation 来进行,例如页面上的操作想要修改 State 数据时,需要通过 Dispatch (触发 Action ),而 Action 也不能直接操作数据,还需要通过 Mutation 来修改 State 中数据,最后根据 State 中数据的变化,来渲染页面。
Vuex 中需要注意的点:
Mutation :是修改State数据的唯一推荐方法,且只能进行同步操作。
Getter :Vuex 允许在Store中定义 "Getter"(类似于 Store 的计算属性)。Getter 的返回值会根据他的依赖进行缓存,只有依赖值发生了变化,才会重新计算。
本段只是简单介绍了一下 Vuex 的运行方式,更多功能例如 Module 模块请参考官网 。
小总结:统一的维护了一份共同的 State 数据,方便组件间共同调用。
四、 \$attrs / \$listeners
Vue 组件间传输数据在 Vue2.4 版本后有了新方法。除了 Props 外,还有了 \$attrs / \$listeners。
Class
和Style
除外)。当一个组件没有声明任何 Prop 时,这里会包含所有父作用域的绑定 (Class
和Style
除外),并且可以通过v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用。下面来看个例子
简单来说,\$attrs 里存放的是父组件中绑定的非 props 属性,\$listeners 里面存放的是父组件中绑定的非原生事件。
小总结:当传输数据、方法较多时,无需一一填写的小技巧。
五、 Provider / Inject
Vue2.2 版本以后新增了这两个 API ,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。简单来说,就是父组件通过 Provider 传入变量,任意子孙组件通过 Inject 来拿到变量。
需要注意的是:Provide 和 Inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
所以,如果采用的是我代码中注释的方式,父级的 name 如果改变了,子组件this.name 是不会改变的,仍然是 政采云,而当采用代码中传入一个监听对象,修改对象中属性值,是可以监听到修改的。
Provider / Inject 在项目中需要有较多公共传参时使用还是颇为方便的。
小总结:传输数据父级一次注入,子孙组件一起共享的方式。
六、 \$parent / \$children & \$refs
this.$parent
访问父实例,子实例被推入父实例的$children
数组中。ref
特性 的所有 DOM 元素和组件实例。ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的$refs
对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件。通过例子可以看到这两种方式都可以父子间通信,而缺点也很统一,就是都不能跨级以及兄弟间通信。
小总结:父子组件间共享数据以及方法的便捷实践之一。
总结
组件间不同的使用场景可以分为 3 类,对应的通信方式如下:
大家可以根据自己的使用场景选择不同的通信方式,当然还是都自己写写代码,试验一把来的印象深刻喽。