一、安装
1.直接下载 / CDN 引用
https://unpkg.com/vuex
Unpkg.com 提供了基于 NPM 的 CDN 链接。以上的链接会一直指向 NPM 上发布的最新版本。您也可以通过 https://unpkg.com/[email protected]
这样的方式指定特定的版本。
在 Vue 之后引入 vuex
会进行自动安装:
2.npm安装:
npm install vuex --save
3.Yarn:
yarn add vuex
二、理解vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
1.为什么会有vuex?
首先我们从我常用的每个组件中的data保存数据的模式开始说起。
这是一个单向数据流的状态管理模式:
这模式在一个组件或者父子组件中是没有问题的,但是当我们遇到多个组件要共享一个状态时,单向数据流的简洁性很容易被破坏:
因此,我们把组件的共享状态抽取出来,以一个全局单例模式管理,就相当于一个大的仓库,这个应用下的所有组件都可以按照vuex定义的规则存储状态(这里不叫做数据,只能叫做状态合适,因为当你刷新浏览器时所有状态是会重置的),而每个组件中的data就相当于每个的小仓库,这里只管理该组件的状态就好了。这样一个应用的数据状态管理就非常有条理,不会混乱。
三、理解vuex的五个核心概念:State、Getter、Mutation、Action、Module
Module(为了防止这个store仓库臃肿而划分的具体子模块):
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割,就像这样numbers.js:
const numbers = {
state:{
account:'sd '
},
mutations:{
ADD_NUMBER:(state,account)=>{
state.account=account
console.log('触发mutations')
}
},
actions:{
addnumber({commit},numbers){
setTimeout(() => {
const accounts= numbers + 10
console.log('触发actions')
commit('ADD_NUMBER', accounts)
}, 1000)
}
}
}
export default numbers
我们先讲module是因为我们要讲两种使用vuex的方式,这两种方式就是使用module模块划分和不使用module模块划分
上面这种就是使用module模块划分的方式,我们来看下使用模块划分的文件结构目录(当然也可以按照自己的想法来划分项目结构):
这种方式就是每个模块都添加到modules文件夹中,像number.js一样,getter.js写每个模块的计算属性,index.js引入每个模块,State:
state就像是组件中的data一样,里面定义的是具体的参数,例如index.js中的state:
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import numbers from './modules/number'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
modules:{
numbers
},
state:{
account:'sd '
},
mutations:{
ADD_NUMBER:(state,account)=>{
state.account=account
console.log('触发mutations')
}
},
actions:{
addnumber({commit},numbers){
setTimeout(() => {
const accounts= numbers + 10
console.log('触发actions')
commit('ADD_NUMBER', accounts)
}, 1000)
}
},
getters
})
export default store
获取state中状态的方式:
1.main.js中全局引入:
import store from './store' // 全局引入
new Vue({
el: '#app',
i18n,
router,
store, // 状态从根组件“注入”
components: { App },
template: ' '
})
当全局引入时,分modules和不分module(直接在store中定义所有的mutation,action)的获取方式又是不一样的,子组件中使用:全局引入时可以在子组件中使用this.$store.state获取state的状态,
不划分模块:this.$store.state.account获取,
划分模块,要写上模块名:this.$store.state.numbers .account获取,若写成this.$store.state.account会报undefined
2.组件中局部引入:import store from '@/store'
局部引入时每个组件都需要引入,有点麻烦。这种方式可以用:store.state获取
不划分模块:store.state.account获取
划分模块,要写上模块名:store.state.numbers .account获取,若写成store.state.account会报undefined
mapState
辅助函数当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性,让你少按几次键:
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'
export default {
// ...
computed: mapState({
// 箭头函数可使代码更简练
count: state => state.count,
// 传字符串参数 'count' 等同于 `state => state.count`
countAlias: 'count',
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
})
}
Getter:
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。 getter接受state作为第一个参数,如getters.js:
const getters = {
account: state => state.numbers.account // 接受state作为第一个参数
}
export default getters
mapGetters
辅助函数:mapGetters
辅助函数仅仅是将 store 中的 getter 映射到局部计算属性
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
Mutation:
更改vuex中的状态的唯一方法是提交mutation,如:commit('ADD_NUMBER', accounts),他接受state作为第一个参数,还可以接受其他传入的参数作为载荷(payload)
注意:mutation中只能写同步函数
你可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
辅助函数将组件中的 methods 映射为 store.commit
调用(需要在根节点注入 store
)。
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
Action:
Action 类似于 mutation,不同在于:
btnclick(){
var that = this
console.log(that.$store.state.account)
this.$store.dispatch('addnumber',that.numbers).then(res =>{
// console.log(that.$store.state.account)
})
}
组件:
计数:{{count}}
点击计数
你在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用 mapActions
辅助函数将组件的 methods 映射为 store.dispatch
调用(需要先在根节点注入 store
):
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
// `mapActions` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
btnclick: 'addnumber' // 将 `this.btnclick()` 映射为 `this.$store.dispatch('addnumber')`
})
}
}
mapActions映射的意思就是当正常写法我们需要绑定一个点击事件btnclick,然后this.$store.dispatch触发action事件,而用了映射则直接像上面的写法即可,少写了this.$store.dispatch触发action事件