一、vuex
1、简介
(1)参考文档
https://vuex.vuejs.org/zh/
(2)vuex指的是一种状态管理模式,集中式管理所有组件的状态。可以将其理解为一个数据仓库,用来集中式存储管理数据。
(3)单向数据流
State:指的就是状态
View:以声明的方式将 state 映射到视图(比如 {{msg}})。
Actions:指的就是响应动作。
简单的理解就是, view 映射 state 到 视图上, 状态发生变化时,触发 Actions,Actions执行完后,更新 state。
2、为什么出现vuex
没使用vuex前,组件间通信处理比较麻烦。
如下图,五个组件,D是B的子组件,E是C的子组件,B、C是A的子组件。现需要D和E组件间传递数据,则需要通过A、B、C三个组件来进行中转,如果出现更多的组件嵌套,那么逻辑可能会很复杂。
如果可以将这个数据放在某个特定的地方,需要用的时候直接去拿,不用通过组件的嵌套传值获得,那么会很方便,可以理解vuex就是为了解决这个问题而诞生的。
3、什么时候使用vuex
(1)小型应用不建议使用,使用的话可能会比较繁琐。
(2)中型、大型单页应用,推荐使用,可以更好地管理组件状态。
二、vuex相关概念
1、State
(1)指的是vuex管理的状态对象。
(2)应该是唯一的。
【形如:】 state : { xxx : initValue // 某个数据的状态 }
2、Mutations
(1)指的是vuex更新state的动作。
(2)包含多个直接更新 state 的方法(回调方法) 的 对象。只能包含同步方法。
【形如:】 mutations: { xxx(state) { // 变更状态 state.xxx } }
3、Actions
(1)类似于 Mutations,只是Actions 提交的是 Mutation,而不是直接更新 state。其可以包含异步操作。
【形如:】 actions: { xxx(context) { commit('xxx') } }
4、Getter
(1)可以理解为计算属性。getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
【形如:】 getters: { xxx: state => { return state.xxx } }
5、使用
(1)安装vuex
npm install vuex --save
(2)引入并映射store
import vuex from 'vuex' import store from './store' Vue.use(vuex) new Vue({ store })
(3)声明一个 Store对象。里面需要包含上述几个属性。
【形如:】 const store = new Vuex.Store({ state: { }, getters: { }, mutations: { }, actions: { } })
三、实例分析
1、普通的vue项目
(1)功能需求:实现一个简单的加减数的功能。如下图:四个按钮,
“+”表示 加1, "-"表示 减1,
"oddAdd"表示只在奇数时加1,"asyncAdd"表示异步的加1(延迟1秒)。
(2)代码实现
目录结构:
import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app') 【App.vue】 <template> <div> {{count}} -- {{addCount}} <br/> <button @click="increase">+</button> <br/> <button @click="decrease">-</button> <br/> <button @click="oddAdd">oddAdd</button> <br/> <button @click="asyncAdd">asyncAdd</button> </div> <!--App --> </template> <script> export default { data() { return { count: 0 } }, computed:{ addCount(){ return (this.count + 2)%2 == 0 ? '偶数' : '奇数'; } }, methods: { increase() { return ++this.count; }, decrease() { return --this.count; }, oddAdd() { return this.count%2 == 0 ? this.count : ++this.count; }, asyncAdd() { setTimeout(() => ++this.count, 1000); } } } </script> <style> </style>
(3)测试截图:
初始画面
点击+
点击 oddAdd
再次点击 oddAdd,值不改变。
点击 -
点击 asyncAdd
2、使用vuex改造上例
(1)目录结构:
(2)代码
【安装vuex】 npm install --save vuex 【store.js】 // 引入组件 import Vue from 'vue' import Vuex from 'vuex' // 使用组件 Vue.use(Vuex) const state = { count : 0 } const mutations = { INCRERASE(state){ state.count++; }, DECRERASE(state){ state.count--; } } const actions = { increase({commit, state}) { commit('INCRERASE') }, decrease({commit, state}) { commit('DECRERASE') }, oddAdd({commit, state}) { if(state.count%2 != 0){ commit('INCRERASE') } }, asyncAdd({commit, state}) { setTimeout(() => commit('INCRERASE'), 1000); } } const getters = { addCount(state){ return (state.count + 2)%2 == 0 ? '偶数' : '奇数'; } } // 向外抛出实例对象 export default new Vuex.Store({ state, // 状态对象 mutations, // 包含多个更新state函数的对象 actions, // 包含多个回调事件的对象 getters // 包含多个计算属性的对象 }) 【main.js】 import Vue from 'vue' import App from './App.vue' import store from './store.js' Vue.config.productionTip = false new Vue({ store: store, // 注册 store render: h => h(App), }).$mount('#app') 【App.vue】 <template> <div> {{$store.state.count}} -- {{addCount}} <br/> <button @click="increase">+</button> <br/> <button @click="decrease">-</button> <br/> <button @click="oddAdd">oddAdd</button> <br/> <button @click="asyncAdd">asyncAdd</button> </div> <!--App --> </template> <script> export default { computed:{ addCount(){ // 此处不要写成 this.$store.getters.addCount() return this.$store.getters.addCount; } }, methods: { increase() { this.$store.dispatch('increase'); }, decrease() { this.$store.dispatch('decrease'); }, oddAdd() { this.$store.dispatch('oddAdd'); }, asyncAdd() { this.$store.dispatch('asyncAdd'); } } } </script> <style> </style>
(3)分析
在Vue实例注册一个 store后, 会全局生成一个 $store。
使用 $store.state 可以获取 state 对象里定义的 状态(数据)。
使用 $store.getters 可以获取 getters 对象里定义的 计算属性。
使用 $store.dispatch 将触发 actions 里的 函数。
actions 通过 commit 触发 mutations 里的函数,从而修改 state。
(4)截图:
与上例一样,此处不再重复截图。
(5)传递参数
按照下面修改代码后,点击 + 按钮,每次可以增加 33。其余按钮可以进行类似的修改。
【dispatch可以传递参数,比如传个对象】 this.$store.dispatch('increase', {name: 'tom', age: 33}); 【actions中可以接收参数,并向mutations 里传】 const actions = { increase({commit, state}, data) { commit('INCRERASE', data) } }, 【mutations中接收参数】 const mutations = { INCRERASE(state, data){ state.count += data.age; } }
3、优化vuex写法
(1)代码优化:
使用 mapState 替代 $store.state
使用 mapGetters 替代 $store.getters
使用 mapActions 替代·$store.dispatch
【优化上例代码】 【App.vue】 <template> <div> {{count}} -- {{addCount}} <br/> <button @click="increase">+</button> <br/> <button @click="decrease">-</button> <br/> <button @click="oddAdd">oddAdd</button> <br/> <button @click="asyncAdd">asyncAdd</button> </div> <!--App --> </template> <script> import {mapState, mapGetters, mapActions} from 'vuex' export default { computed:{ ...mapState(['count']), ...mapGetters(['addCount']) }, methods: { ...mapActions(['increase', 'decrease', 'oddAdd', 'asyncAdd']) } } </script> <style> </style>
截图一样,此处不重复截图。
(2)传递参数
可以再定义一个方法,进行参数传递。
如下,每次点击 + 按钮,可以增加 20。其余按钮可以类似的修改。
【绑定一个事件】 <button @click="test">+</button> 【事件再触发 actions中的函数】 methods: { ...mapActions(['increase', 'decrease', 'oddAdd', 'asyncAdd']), test() { this.increase({name: 'tom', age: 20}) } } 【actions 接收参数,并传递给mutations 】 const actions = { increase({commit, state}, data) { commit('INCRERASE', data) } } 【mutations 接收参数并更改state】 const mutations = { INCRERASE(state, data){ state.count += data.age; } }