个人见解,如有问题,欢迎指正。
1、一句话描述vuex:
对‘vue应用’多个组件的共享状态进行集中式管理的一个vue插件。
2、vuex主要用来解决:
多个视图(不同组件)依赖同一状态,对来自不同视图的行为需要变更同一状态,也可以理解为组件通信用。比如说一个列表页,头部有个搜索(组件),中间是列表数据(组件),下面是增删改按钮(组件),三个组件都需要对列表数据进行操作,就可以用vuex解决,但是不太合适,因为定义已经描述了。适合中大型单页应用,考虑如何更好地在组件外部管理状态,简单应用不建议使用。
3、vuex管理共享状态的图(理解了这个图,使用起来就简单了)
vuex的4个核心概念:state,getters,actions,mutations都是对象
state:管理数据状态的一个容器,唯一数据源,相当于vue组件中的data,它渲染给vue组件
getters:对存储的数据(也就是state中的数据)进行计算操作然后返回的容器,相当于vue组件中的computed,计算后渲染给vue组件($store.getters.xxx)
actions:存储回调函数(与组件中事件函数是对应关系)的一个容器,vue组件通过this.$store.dispatch(‘action里面的函数名称’,data)分发给它,间接更新数据,因为他还要通过commit('mutaions里面的函数',{data})触发mutations,另外它可以通过ajax请求后台api接口,调用数据
mutations:包含多个直接更新state的方法一个容器,actions触发mutations直接更新state对象(只有它可以直接更新state),
devtools可以通过该工具监视mutations
4、如何使用vuex(很多描述都是写在代码注释中啦)
在项目src目录下新建store\index.js
src\store\index.js代码
import Vue from 'vue'
import Vuex from 'vuex'
//state,actions,mutations,getters可以从外面引入,正常情况也下也是从外面,易于维护和分离
//import state from './state.js'
//import actions from './actions .js'
//import mutations from './mutations .js'
//import getters from './getters .js'
Vue.use(Vuex)
const state = {
count: 0
}
///包含多个对应事件函调函数的对象
const actions = {
increment ({commit}) {
//提交一个mutations
commit('INCREMENT')
},
decrement ({commit}) {
commit('DECREMENT')
},
incrementOdd ({commit, state}) {
if (state.count%2 === 0) {
commit('INCREMENT')
}
},
incrementAsync ({commit}) {
setTimeout( () => {
commit('INCREMENT')
}, 1000);
},
//传递数据也是在数据的外层包裹大括号,以对象形式{data}
// incrementAsync ({commit}, data) {
// setTimeout( () => {
// commit('INCREMENT', {data})
// }, 1000);
// },
}
/包含多个更新state函数的对象
const mutations = {
///增加的mutation
INCREMENT (state) {
state.count++
},
// 接收数据也是在数据的外层包裹大括号,以对象形式{data},注意!!!
// INCREMENT (state, {data}) {
// state.count++
// //return {data}
// },
///减少的mutation
DECREMENT (state) {
state.count--
}
}
/包含多个getter计算属性函数的对象
const getters = {
evenOrOdd (state) {
return state.count%2 === 0 ? '偶数' : '奇数'
}
}
//向外暴露,初始化Store对象
export default new Vuex.Store({
state,
actions,
mutations,
getters
})
然后是在入口文件main.js中注册该组件,也就是映射,然后就可以使用vuex了
import Vue from 'vue'
import App from './App'
import store from './store/index.js'///引入
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
store注册
})
src\App.vue中使用
<template>
<div id="app">
<p>click {{$store.state.count}} <!--在vue中注册vuex,该组件就有了,this.$store对象-->times, count is {{evenOrOdd}}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">increment if odd</button>
<button @click="incrementAsync">increment async</button>
</div>
</template>
<script>
import {mapState, mapGetters, mapActions} from 'vuex'
export default {
computed: {
// evenOrOdd () {
// return this.$store.getters.evenOrOdd
// }
// 在vue中注册vuex,该组件就有了,this.$store对象
...mapState(['count']),
...mapGetters({evenOrOdd: 'evenOrOdd'}) //这是对上面注释evenOrOdd简洁写法,封装
},
methods: {
...mapActions(['increment', 'decrement', 'incrementOdd', 'incrementAsync'])
//这是对下面注释increment,decrement,incrementOdd,incrementAsync 简洁写法,封装
// increment () {
// //通知vuex去更新,触发store中对应的action调用
// this.$store.dispatch('increment')
// },
// decrement () {
// //通知vuex去更新
// this.$store.dispatch('decrement')
// },
// incrementOdd () {
// //通知vuex去更新
// this.$store.dispatch('incrementOdd')
// },
// incrementAsync () {
// this.$store.dispatch('incrementAsync')
// }
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
├── getters.js # 根级别的 getters
└── modules
├── cart.js # 购物车模块, 产品模块,每个模块中都包含一个actions,getters,state,mutations
└── products.js # 这样的好处是根级别相对应的对象不会太大,易于容易维护调试