vuex是专为vue开发的一个状态管理库。它集中存储管理应用所有组件的状态。
你可以在应用内的任意一个组件中获取、修改vuex里的状态,一处修改,全局更新状态。再也不用往子孙组件一层一层传递数据了,是不是感觉很痛快。接下来带你们快速掌握vuex
//npm
npm install vuex --save
//yarn
yarn add vuex --save
--save 会记录到package.json 的dependencies 中,代表项目需要的意思,不论生产环境还是开发环境,项目都会使用。默认就是--save ,在命令行中也可以不写。
store 仓库,容器的意思。一个项目的所有状态都存在store中。vuex提供了获取、修改仓库状态的办法,我会在文章下面列出两个办法。现在不着急,我们接着了解vuex的几个核心概念。
单一状态树,存放状态的对象。
获取state
this.$store.state.user
辅助函数mapState
在一个组件中,如果要使用多个状态,可以使用mapState将state声明计算属性。然后使用计算属性的值
computed:mapState({
user: user => state.user,
sex_text: sex => state.sex==1?'男':(state.sex==2?'女':'—'),
sex: sex => state.sex
})
上面通过计算属性将性别转换成男或女。
通过拓展符号来实现
computed:{
geN(){}, //组件的其他计算属性
...mapState({
user: user => state.user,
sex_text: sex => state.sex==1?'男':(state.sex==2?'女':'—'),
sex: sex => state.sex
})
}
在组件中使用
<div>{{sex_text}}</div>
初始化state
state:{
user:'admin',
nickName:'',
sex:1, //1 男 2 女
}
派生state状态,就是对state的状态进行二次处理,返回处理之后的状态。
下面例子中,getter 筛选state状态树中的列表。
const store = createStore({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
// 将todos列表中done为true的全部筛选出来
doneTodos (state) {
return state.todos.filter(todo => todo.done)
},
//查找todos为中id对应的对象
getId:(state)=>(id) => {
return state.todos.find(todo=>todo.id === id)
}
}
})
辅助函数mapGetters
将store中的getter映射到当前组件中。
// 获取getter的派生状态
computed:mapGetters([
'doneTodos'
])
// 给派生状态起别名
computed:mapGetters({
doneTodosCount: 'doneTodos'
})
// 扩展符,不影响组件自身使用计算属性
computed:{
...mapGetters({
doneTodosCount: 'doneTodos'
})
}
模板中使用
<template>
<ul>
<li v-for="(item,index) in doneTodosCount" :key="index">{{item.text}}</li>
</ul>
</template>
更改state状态 ,提交mutations的方法来更改state。
const store = createStore({
state: {
count: 1,
userinfo:{}
},
mutations: {
increment (state) {
// 变更状态
state.count++
},
//修改用户信息
getUser(state,payload){
state.userinfo = payload
}
}
})
通过一个state参数来实现改变状态。调用mutations下的increment方法来实现state.count自增1。
this.$store.commit('increment')
通过两个参数来更新状态,第二个参数payload。通过commit传递状态来更新。
this.$store.commit('getUser' ,{
name:'admin',
nickName:'hil'
})
//对象形式的写法
this.$store.commit({
type:'getUser',
name:'admin',
nickName:'hil'
})
模板中使用更新的count
<template>
<div>{{$store.state.count}}</div>
</template>
提交mutations ,而不是直接提交state。action是异步操作。
提交mutations
actions: {
increment ({ commit }) {
commit('increment')
}
}
辅助函数mapActions
methods:{
...mapActions([
'increment'
]),
...mapActions({
add:'increment'
})
}
执行更新
//直接分发
this.$store.dispatch('increment')
//通过mapActions来分发
this.increment()
//通过mapActions 设置别名的调用方法
this.add()
组合actions
将多个异步actions,进行组合执行。使用async/await 按顺序执行。
actions: {
async one ({ commit }) {
commit('gotData', await getData())
},
async two ({ dispatch, commit }) {
await dispatch('one') // 等待 one 完成
commit('gotData2', await getData2())
}
}
将store 分割成模块,避免一个store过大造成臃肿。实际上还是一个大的store,只是通过modules 将大的store分割成很多小的store。每个模块都拥有自己的 state、mutation、action、getter。
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
带上模块名使用
this.$store.state.a
本例简单创建一个vuex全流程的状态管理库,使用环境为vue2.x + vuex3.x。
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
import store from './store.js'
new Vue({
store,
render: h => h(App),
}).$mount('#app')
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import modelA from './modelA.js'
const store = new Vuex.Store({
module:{
a:modelA
}
})
export default store
modelA.js
const modelA = {
state:{
number:0
},
mutations:{
increment(state){
state.number++
},
decrement(state) {
state.number--
}
}
}
export default modelA
app.vue
<template>
<div>
<button @click="$store.commit('increment')">点击+1</button>
{{$store.state.a.number}}
<button @click="$store.commit('decrement')">点击-1</button>
</div>
</template>
<script>
export default {
data(){
return{}
},
}
</script>
如何在模块中避免冲突,了解vuex 命名空间