概述

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: '
<app />'
})


 

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

现在我们来看父组件:

<template>
<yd-layout>
<p>这是一个Todo-List示例</p>
<hw-add></hw-add>
<hw-list></hw-list>
<p>todoList 总数:{{listCount}}</p>
<p>{{msg}}</p>
</yd-layout>
</template>

<script>
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
});
}
}
}
}
</script>


Main.vue用来展示列表和添加列表项等子组件,已经显示列表长度和错误信息提示。我们看到在 computed 中获取到数据仓库中的数据,并显示在页面上。

 

6. Add.vue

Add.vue用来添加列表项。

<template>
<yd-layout>
<yd-cell-group>
<yd-cell-item>
<yd-icon slot="icon" name="discount" size=".35rem"></yd-icon>
<input type="text" slot="right" placeholder="请输入内容" v-model="value" @keyup.enter="addItem">
<yd-button slot="right" type="warning" @click.native="addItem">新增</yd-button>
</yd-cell-item>
</yd-cell-group>

</yd-layout>
</template>

<script>
export default {
data() {
return {
value: '',
id: 0
}
},
methods: {
addItem() {
let item = {
value: this.value,
id: ++this.id
}
this.value = '';
this.$store.dispatch('addTodo', item);
}
}
}
</script>


在添加列表项的addItem方法中,我们使用 this.$store.dispatch('addTodo', item); 告诉vuex的 addTodo ,我们要往todo list中添加新的列表项。

7. List.vue

List.vue用来展示列表项,并且提供删除列表项功能。

<template>
<yd-layout>
<yd-cell-group title="Todo列表">
<yd-cell-item v-for="(item,index) in todoList" :key="index" class="list">
<span slot="left">{{index+1}}.{{item.value}}</span>
<span slot="right">
<yd-icon slot="icon" name="delete" size=".36rem" @click.native="del(index)"></yd-icon>
</span>
</yd-cell-item>
</yd-cell-group>
</yd-layout>
</template>

<script>
import {mapState} from 'vuex';

export default {
data() {
return {

}
},
computed: {
...mapState([
'todoList'
])
},
methods: {
del(index) {
this.$store.dispatch('delTodo', index);
}
}
}
</script>


上述代码中的

computed: {
...mapState([
'todoList'
])
},


其实相当于:

computed: {
todoList() {
return this.$store.state.todoList;
}
},


 

小结

通过示例我们可以知道,使用Vuex来管理数据共享,各组件无需关注组件间的数据通信传输,一切数据的读取和更新都是各组件与Vuex数据仓库间的操作,避免了复杂项目中数据管理混乱的情况发生。

Vuex的使用还有很多优化的写法,比如 mapState、mapGetters、mapActions ,本站后面会有文章讲解。当然,如果是小型的项目,我们直接用$emit, props等就能解决组件间的数据通信问题,不必使用vuex这个伤脑筋的工具。