简介
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说,用来集中管理数据,类似于React中的Redux,都是基于Flux的前端状态管理框架
基本用法
以官方例子为例:
当点击+1按钮的时候,count 加1,点击-1按钮的时候,count 减1.
安装vuex
cnpm install vuex -S12
创建store.js文件,在main.js中导入并配置store.选项
import store from './store.js'new Vue({ el: '#app', router, store, template: '<App/>', components: { App } })123456789
编辑store.js文件
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex);//数据 var state = { count: 10} //获取数据 var getters = { count(state){ return state.count; } } //异步动作 const actions = { add({commit,state}){ commit('add'); }, sub({commit,state}){ commit('sub'); } } //同步动作 const mutations = { add(state){ state.count++; }, sub(state){ state.count--; } } const store = new Vuex.Store({ state, getters, actions, mutations }) export default store;123456789101112131415161718192021222324252627282930313233343536373839404142434445
Vuex的核心是Store(仓库),相当于是一个容器,一个store实例中包含以下属性的方法: state 定义属性(状态、数据) getters 用来获取属性 actions 定义方法(动作) commit 提交变化,修改数据的唯一方式就是显式的提交mutations mutations 定义变化 注:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化 12345678
编辑App.vue
在子组件中访问store对象的两种方式:
通过this.$store访问
通过mapState、mapGetters、mapActions访问
mapState 获取state mapGetters 获取getters mapActions 获取actions
1
2
3
4
<template> <div id="app"> <p>{{count}}</p> <button @click="add">+</button> <button @click="sub">-</button> </div></template><script>import {mapGetters,mapActions} from 'vuex'export default { name: 'app', data() { return { } }, // computed:{ //方式一 // count(){ // return this.$store.state.count; // } // }, computed:{ ...mapGetters([ 'count' ]), msg(){ console.log("同时使用mapGetters和自定义computed"); } }, //computed:mapGetters([ // 'count' //]), methods:mapActions([ 'add', 'sub' ]) }</script><style> a { text-decoration: none; }</style>12345678910111213141516171819202122232425262728293031323334353637383940414243444546
探究
我们再看一张图
很多人会疑惑:
为什么要有actions和mutations?
我为什么要在action里调用mutations然后由mutations去修改state?
为什么不可以在mutations里直接去修改state?
官方的说法是:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化
我们也经常听到actions是异步动作,mutations是同步动作,那么该怎么去理解呢?
我举一个例子,也许你就会豁然开朗!
假如你是一个君王,前方正在打仗。每隔一段时间前线就来一个探子汇报战况:
“报!!! 我们还有1500军队,弟兄们快顶不住了!!”
这就是getters的作用了
<span>我军军队:{{count}}</span> computed:mapGetters([ 'count' ]), var getters = { count(state){ return state.count; } }1234567891011
于是你慌了,你命令道:
“不行,赶快撤军,速度跑路!!”
<button @click="chejun">撤军</button> methods: { chejun(){ this.$store.dispatch("chejun"); } }1234567
于是探子把你的命令传给了前线元帅。
元帅看到你的圣旨上两个大字:“撤军”
他会怎么做?会立马撤军吗?
不会吧,他要进行各方面的准备和筹划吧!**
这就是actions的作用了
//异步动作 进行逻辑判断,异步请求,错误处理 const actions = { chejun({commit,state}){ console.log("今晚开始撤军!!"); if(state.count >= 10000){ console.log("赵四你带3000人掩护"); }, else if(state.count >= 5000){ console.log("赵四你带500人掩护"); }, else if(state.count >= 1000){ console.log("赵四你带50人摆空城记"); } console.log("其他人随我出城!!"); commit('chejun'); } }1234567891011121314151617
元帅的命令下来了以后,士兵们执行就好了
这就是matations的作用了
//同步动作 立马就去执行const mutations = { chejun(state){ state.count = 0; } }123456
例子虽然不太恰当,但是你应该明白为什么要有actions和mutations了吧。为什么叫actions异步,mutations同步了吧。
进阶
明白了vuex的基本用法和逻辑结构后,我们再探讨下vuex的项目结构
项目结构
Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
应用层级的状态应该集中到单个 store 对象中。
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
异步逻辑都应该封装到 action 里面
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
├── index.html ├── main.js ├── api │ └── ... # 抽取出API请求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 我们组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation └── modules ├── cart.js # 购物车模块 └── products.js # 产品模块123456789101112131415
我们把上面的例子改进一下
这是项目结构图
子模块
user.js
/** * 用户模块 */import types from '../types.js' //从types.js中引用常量 const state={ count:6 } var getters={ count(state){ return state.count; } }const actions = { increment({commit,state}){ commit(types.INCREMENT); //提交一个名为increment的变化,名称可自定义,可以认为是类型名 }, decrement({commit,state}){ if(state.count>10){ commit(types.DECREMENT); } } }const mutations={ [types.INCREMENT](state){ state.count++; }, [types.DECREMENT](state){ //es6语法:[]内的视为常量 state.count--; } } export default { state, getters, actions, mutations }12345678910111213141516171819202122232425262728293031323334353637383940414243
公共actions
actions.js
import types from './types.js'const actions={ incrementAsync({commit,state}){ //异步操作 var p=new Promise((resolve,reject) => { setTimeout(() => { resolve(); },3000); }); p.then(() => { commit(types.INCREMENT); }).catch(() => { console.log('异步操作'); }); } }export default actions;123456789101112131415161718192021
公共getters
getters.js
const getters={ isEvenOrOdd(state){ return state.user.count%2==0?'偶数':'奇数'; } } export default getters;1234567
常量模块
type.js
/** * 定义类型常量 */const INCREMENT='INCREMENT'const DECREMENT='DECREMENT'export default { INCREMENT, DECREMENT }1234567891011
根模块
index.js
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex);import getters from './getters.js'import actions from './actions.js'import user from './modules/user.js'export default new Vuex.Store({ getters, actions, modules:{ //这里存放的是子模块 user } });12345678910111213141516