官方上介绍:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具devtools extension
,提供了诸如零配置的time-travel
调试、状态快照导入导出等高级调试功能。
经过短暂接触,个人感觉Vuex有点像一个中转站,你可以将一些数据存到Vuex中,然后项目中的各个地方可以从Vuex中共享这些数据。
在做项目的过程中,当你需要跨组件共享数据,或者缓存一些数据的时候,可以通过Vuex来实现,当然组件之间的数据传递也可以通过bus
、传参等方法,但是在多层嵌套的组件中去使用这些方法会变得很繁杂,不利于维护。因此Vuex是一个更好的选择。
当然如果应用足够简单,那就不需要使用Vuex,一个简单的store
模式就足够使用了,这里不在描述store
模式,可在官网上自行阅读
以下是Vuex的说明图,从图中可以看出,Vuex主要有三个部分组成,分别为State、Actions、Mutations,可以将其看为一个store
,其中所有的公用数据都存储在State区域中。
如果需要修改State区域中的数据,必须要经过特定的流程:如果有一些异步操作或者一些比较复杂的、批量的同步操作可以在组件中通过dispatch
方法去调用Actions,然后Actions通过commit
方法去调用Mutations,Mutations在通过mutate
方法去修改State中的数据;当然如果只是一些简单的操作,可以跳过Actions,让组件通过commit
方法直接去调用Mutations去修改State的数据
这里的使用是在以vue-cli脚手架工具搭建的条件下的
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 # 产品模块
(1).如果是直接在html文件中引用,可以直接在引入Vue之后引入vuex会进行自动安装
<script src="/path/to/vue.js">script>
<script src="/path/to/vuex.js">script>
(2).npm可以通过以下命令进行安装
npm install vuex --save
(3).创建store
并引入
在一个模块化的打包系统中,必须显式地通过Vue.use()
来安装Vuex,根据Vue推荐的项目结构,我们可以在项目src目录下创建store文件夹并在新建index.js文件,写入以下代码来创建一个store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
city: '北京'
}
})
然后在main.js中通过以下代码引入
……
import store from './store'
new Vue({
……
store,
……
})
在上文中我们已经成功的安装Vuex,创建了一个store
并引入到vue实例当中,此时在其他任何需要使用到vuex数据的组件中都可以通过this.$store.state.city
来获取数据
在项目中修改store
中的共享数据city
具体需要经过以下步骤:
(1).首相让组件通过调用store
实例的dispatch
函数去调用store
中的actions
属性中的方法,dispatch
函数的第一个参数是actions
中的方法名称,第二个参数是传递的值;
(2).然后actions
的对应方法会接收到两个参数,分别为上下文对象和传递的值,在方法中通过调用上下文对象的commit
函数来调用store
中的mutations
属性中的方法,commit
函数也需要传递两个参数,与dispatch
一样;
(3).最后,mutations
中的对应方法会接收到两个参数,一个是store
中的state
对象即存放数据的对象,第二是传递过来的值,在方法对state
对象中的目标数据进行修改即可
当然,如果只是简单的修改数据,不涉及异步、批量等操作的时候,可以跳过actions
,直接让组件通过commit
方法调用mutations
即可
而在修改数据时候因为要用到actions
与mutations
所以在src/store/index.js创建store
时应该为其定义这些属性
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
city: '北京'
},
actions: {
funcNameA (cxt, city) {
cxt.commit('changeCity', city)
}
},
mutations: {
changeCity (state, city) {
state.city = city
}
}
})
再在App.vue文件中编写以下内容
<template>
<div id="app">
<div>{{this.$store.state.city}}div>
<button @click="handleClick('上海')">上海button>
div>
template>
<script>
export default {
name: 'App',
methods: {
handleClick (city) {
alert(city)
this.$store.commit('changeCity', city)
}
}
}
script>
<style>
style>
至此,Vuex简单的数据获取以及数据修改操作就完成了
在上述代码中,我们把actions
、mutations
、state
的相关代码都放在了index.js中,按照官方推荐的目录结构,应该分别拆分为三个js文件,这样有利于项目代码的维护,层次也更加分明
首先我们在src/store目录下创建state.js文件,并将目前src/store/index.js中与state.js相关的部分抽取出来
export default {
city: '北京'
}
mutations
与actions
也如法炮制,当然如果项目中只用到了mutations
,name actions
可以省去,之后再在index.js中引入使用即可
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state.js'
import mutations from './mutations.js'
import actions from './actions.js'
Vue.use(Vuex)
export default new Vuex.Store({
state,
actions,
mutations
})
Vuex中提供了getters
属性,作用与用法类似与vue实例中的computed
属性,区别在于getters
中定义的方法默认会接收到state
对象作为入参,当我们需要根据state
数据来处理或计算数据的时候,可以通过getters
来定义方法得到计算值,避免冗余
export default new Vuex.Store({
state,
actions,
mutations,
getters: {
cityNo (state) {
return state.city + ' 01'
}
}
})
Vuex中提供了一些用于映射的方法,如:mapState
、mapMutations
、mapActinos
、mapGetters
等,可以在需要使用Vuex的组件中通过
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
来引入
引入了vuex提供的映射方法之后,可以通过...mapState(……)
对store
对应的属性进行展开并映射到vue实例当中,具体做法如下:
- mapState
、mapGetters
一般是映射在computed
属性中的
(1).数组形式展开映射
将store
中state
的city
映射到computed
属性的city
上
computed: {
...mapState(['city'])
}
(2).对象形式展开映射
将store
中state
的city
映射到computed
属性的currentCity
上
computed: {
...mapState{
currentCity: 'city'
}
}
mapMutations
、mapActions
等一般都映射在methods
属性中,用法与mapState
一样,之后通过this.reflectName
来调用方法即可唔。。后续再更新