Vuex与组件通信
概述
Vuex
是一个专为 Vue.js 应用程序开发的状态管理模式。也就是说 Vuex 用于单页面应用组件之间的数据共享,在组件嵌套很多层的情况下,Vue 中父子组件的通信过程就变得很麻烦,此时使用 Vuex 方便了组件间的通信。
vuex官网上说是一个vue的状态管理工具。其实我们可以简单地把状态理解成为vue的data里面的变量。当组件之间的data变量关系复杂一点的时候,就把其中的变量抽离出来管理。
Vuex提供了一个数据仓库,存放着各种数据data。谁要用谁去请求num的值,谁想改就改该多好是吧,vuex就是干这个的,有点全局变量的意思。任何组件需要拿,改东西,都可以找他。
Vuex主要涉及到state,getters,mutations,actions。
state
:是驱动应用的数据源,是惟一的数据载体,跟仓库一样。
mutations
:更改state的唯一方法,意思是修改、增加等处理state的方法,
getters
:从state中派生出的一些状态,如获取数据的数组的长度,方便其他组件获取使用。简单来说,就是过滤,计算,组合!
actions
:用来提交mutations,通过commit再去触发对应的mutations,而不是直接变更state状态。
稍微简单点的vuex管理就使用 state
和 mutations
这两个就行。复杂的vuex管理还会涉及到modules等辅助方法。
应用实例:Todo-list
本文旨在通过一个简单的todo list例子,熟悉vuex常见的方法,了解组件间数据共享机制。
本文示例中,分为父组件Main.vue,两个子组件List.vue和Add.vue,父组件包含两个子组件,实时显示列表长度,子组件Add.vue负责添加列表项,List.vue负责显示列表,以及删除列表项。在子组件添加和删除列表项时,相应的组件会联动:父组件会实时计算列表长度,List组件会增减列表项。大家可以先观看效果:Demo。
1. 准备
本实例采用 Vue2
+ Vue Router
+ Vuex
+ vue-ydui
实现。 我们事先已经建立了Vue webpack模板,并安装相关组件。
npm install --save vuex npm install --save vue-router npm install --save vue-ydui
2. 建立数据仓库
在src目录下建立文件夹store/,并在store/目录下新建index.js文件。
import Vue from 'vue' import Vuex from "vuex" Vue.use(Vuex) const store = new Vuex.Store({ state: { message: '', todoList: [{id: 0, value: 'default'}] }, getters: { //计算list长度 listCount(state) { return state.todoList.length; } }, mutations: { //新增 addTodo(state, item) { state.todoList.push(item); }, //删除 delTodo(state, index) { state.todoList.splice(index, 1); }, //设置错误提示信息 showError(state, msg) { state.message = msg; } }, actions: { //提交addTodo addTodo(context, item) { if (item.value == '') { context.commit('showError', '请输入内容'); } else { context.commit('addTodo', item); context.commit('showError', ''); } }, //提交delTodo delTodo({commit}, index) { commit('delTodo', index); } }, modules: {} }); export default store;
如上代码和注释,我们在store/index.js中设置了数据以及修改这些数据的方法。
3. main.js
在main.js中将store.js加进来。示例中我们还用到了UI库:vue-ydui,也一起加进来。
import Vue from 'vue' import App from './App' import router from './router' import store from './store' import YDUI from 'vue-ydui'; import 'vue-ydui/dist/ydui.rem.css'; Vue.use(YDUI); Vue.config.productionTip = false new Vue({ el: '#app', router, store, components: { App }, template: ' ' })
4. 设置路由
在router/index.js加入路由设置,让页面直接访问父组件Main.vue。
import Vue from 'vue' import Router from 'vue-router' import Main from '@/components/Main' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'Main', component: Main } ] })
5. Main.vue
现在我们来看父组件:
这是一个Todo-List示例 todoList 总数:{{listCount}} {{msg}} import hwAdd from "./Add.vue"; import hwList from "./List.vue"; export default { components: { hwAdd, hwList }, data(){ return { } }, computed: { listCount() { return this.$store.getters.listCount; }, msg() { let message = this.$store.state.message; if (message !== '') { this.$dialog.toast({ mes: message, timeout: 1500 }); } } } }
Main.vue用来展示列表和添加列表项等子组件,已经显示列表长度和错误信息提示。我们看到在 computed
中获取到数据仓库中的数据,并显示在页面上。
6. Add.vue
Add.vue用来添加列表项。
新增 export default { data() { return { value: '', id: 0 } }, methods: { addItem() { let item = { value: this.value, id: ++this.id } this.value = ''; this.$store.dispatch('addTodo', item); } } }
在添加列表项的addItem方法中,我们使用 this.$store.dispatch('addTodo', item);
告诉vuex的 addTodo
,我们要往todo list中添加新的列表项。
7. List.vue
List.vue用来展示列表项,并且提供删除列表项功能。
{{index+1}}.{{item.value}} import {mapState} from 'vuex'; export default { data() { return { } }, computed: { ...mapState([ 'todoList' ]) }, methods: { del(index) { this.$store.dispatch('delTodo', index); } } }
上述代码中的
computed: { ...mapState([ 'todoList' ]) },
其实相当于:
computed: { todoList() { return this.$store.state.todoList; } },
小结
通过示例我们可以知道,使用Vuex来管理数据共享,各组件无需关注组件间的数据通信传输,一切数据的读取和更新都是各组件与Vuex数据仓库间的操作,避免了复杂项目中数据管理混乱的情况发生。
Vuex的使用还有很多优化的写法,比如 mapState、mapGetters、mapActions
,本站后面会有文章讲解。
当然,如果是小型的项目,我们直接用$emit, props等就能解决组件间的数据通信问题,不必使用vuex这个伤脑筋的工具。
注意:Vuex 是将数据存储在了内存中,每一次刷新页面,之前存在 Vuex 中的数据就会重新初始化。