概述
Vuex 是一个专为 Vue.js 应用程序开发的状态管理
模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
对于组件间的通信方式而言,vuex也是一个可以进行任意组件通信的方法。
使用场景:
- 某个状态在很多组件来使用(个人信息)
- 多个组件共同维护一份数据(购物车)
优势:
- 共同维护一份数据,数据集中化管理
- 响应式变化
- 操作简洁(vuex提供了一些辅助函数)
组件间共享数据的方式
- 父向子传值:v-bind属性绑定
- 子向父传值:v-on事件绑定
- 兄弟组件之间共享数据:EventBus
- $on 接收数据的组件
- $emit 发送数据的组件
Demo案例
当组件变化时对应的其他组件的值也会发生变化。说白了,操作的是共享数据,一旦发生变化,能够影响到所有使用到它的值。
创建一个空仓库
-
目标:安装vuex插件,初始化一个空仓库
npm install vuex --save
-
新建 store/index.js 专门存放vuex
-
Vue.use(Vuex)创建仓库 new Vuex.Store()
-
在main.js中导入挂载到Vue实例上
核心概念-state状态
目标:明确如何给仓库 提供 数据,如何使用仓库的数据
提供数据
state 提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储,在state对象中可以添加我们要共享的数据。
使用数据
- 通过store直接访问
获取store:
1.this.$store
2.import store from './store'
模板中:{{$store.state.xxx}}
组件逻辑中:this.$store.state.xxx
js模块中: store.state.xxx
- 使用计算属性
将vuex仓库中的数据,通过计算属性的方式封装起来,当调用的时候只需要写计算属性的名称,这样方便同时简洁
- 通过辅助函数
使用mapState
是辅助函数,帮助我们把store中的数据自动
映射到组件的计算属性中
使用步骤:
- 导入mapState---> import {mapState} from 'vuex'
- 数组方式引入state---> mapState(['count'])
- 展开运算符映射
核心概念-mutations
目标:明确vuex 同样遵循单向数据流,组件中不能直接修改仓库的数据
在这里于prop一致,父组件传递个子组件的数据, 子组件不能直接修改,子组件需要给父组件传递信息让父组件去修改,而vuex一样,对于组件来说,需要修改数据,需要通知vuex。此时可以用到mutations
-
定义mutations对象,对象中存放修改state的方法
-
组件中提交调用mutations
this.$store.commit('addCount')
太麻烦了
对于上诉使用mutations来说,同一类型的调用,需要定义不同的mutations方法,太冗余了,此时可以通过mutations传参的方式。
语法
:this.$store.commit('xxx',参数)
xxx表示方法名,在mutations中定义好的。
1-通过mutation函数(带参数-提交载荷payload)
mutations: {
// 定义修改仓库中数据的方法,第一个参数是当前store的state属性
// 第二个参数是载荷,也就是其他组件传递过来的参数
addCount (state, n) {
state.count += n
},
delCount (state, n) {
state.count -= n
}
}
2-在组件中调用
methods: {
handledel () {
this.$store.commit('delCount', -1)
}
}
注意
:在传参的过程中,只能传递一个参数,要想传递多个参数,请用对象的形式。
例如:
辅助函数:mapMutations
mapMutations
和 mapState
很像,它是把位于mutations
中的方法提取出来,映射到组件methods中
示例:
这是在仓库中定义的方法
// 定义mutations
mutations: {
// 定义修改仓库中数据的方法,第一个参数是当前store的state属性
addCount (state, n) {
state.count += n
},
delCount (state, n) {
state.count -= n
},
changeObj (state, obj) {
state.count += obj.count
},
changeNum (state, num) {
state.count = num
}
}
如果我们要在组件中调用这些方法需要this.$store.commit('xxx',参数)
去调用
可以通过mapMutations
去让方法产生映射关系:记住它是在方法中去映射的
methods: {
// mapMutations 将仓库中定义的方法映射到组件中,直接调用即可
...mapMutations(['addCount', 'delCount', 'changeObj', 'changeNum']),
handledel (num) {
this.delCount(num)
}
}
核心概念-actions
在 Vuex 中,actions 是用于处理异步操作的地方,例如从服务器获取数据、定时器、或者其他需要异步处理的任务。actions 提交 mutations 来修改 state,而不是直接修改 state。
需求:一秒钟后在将数据改变,例如:
实现步骤:
- 在仓库中提供一个 action方法,该方法用一个定时最后再去执行mutations中的方法。
- 页面中通过
this.$store.dispatch('action的方法',参数)
调用
对于actions来说,一般的场景使用就是发起请求。
辅助函数-mapActions
mapActions
是把位于 actions中的方法提取出来,映射到组件methods中
它跟 mapState、mapMutations是一样的,都是将仓库中的数据或者方法,映射到组件中从而简化代码。
核心概念-getters
类似于计算属性 computed
说明:除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters
例如:state中定义了list,为1-10的数组,组件中,需要显示所有大于5的数据
state:{
list:[1,2,3,4,5,6,7,8,9,10]
}
- 1.定义getters
getters:{
// 注意
//1.getters函数的第一个参数是 state
//2.getters函数必须要有返回值
filterList(state){
return state.list.filter(item=>item>5)
}
}
- 2.访问getters
- 通过store访问getters
{{$store.getters.filterList}}
- 通过辅助函数 mapGetters映射
computed:{ ...mapGetters(['filterList']) } // 使用 {{filterList}}
- 通过store访问getters
核心概念-模块 module(进阶语法)
由于vuex使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿,当项目变得越来越大的时候,vuex会变得越来越难以维护
模块拆分
例如user模块:store/modules/user.js
// user模块
// State(状态)
const state = {
userInfo: {
name: 'zs',
age: 18
},
score: 80
}
//Mutations(同步修改状态)
const mutations = {
}
//Actions(异步修改状态)
const actions = {
}
//Getters(计算属性)
const getters = {
}
// 对外暴露
export default {
namespaced: true, // 开启命名空间,用于mapState 映射
state,
mutations,
actions,
getters
}
将模块挂载到仓库中
import user from './modules/user'
const store = new Vuex.Store({
modules:{
user
}
})
组件使用:
尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的state中,属性名就是模块名
- 直接通过模块名访问
$store.state.模块名.xxx
- 通过mapState映射
默认根级别的映射mapState(['xxx'])
子模块的映射mapState('模块名',['xxx'])
-需要开启命名空间
使用模块中getters中的数据:
- 直接通过模块名访问
$store.getters['模块名/xxx']
- 通过
mapGetters
映射
默认根级别的映射mapGetters(['xxx'])
子模块的映射mapGetters('模块名',['xxx'])
-需要开启命名空间
// 对外暴露
export default {
namespaced: true, // 开启命名空间
state,
mutations,
actions,
getters
}
调用子模块中mutation
:
- 直接通过store调用
$store.commit('模块名/xxx',额外参数)
- 通过mapMutations映射
默认根级别的映射mapMutations(['xxx'])
子模块的映射mapMutations('模块名',['xxx'])
-需要开启命名空间
调用子模块 actions
:
- 直接通过store调用
$store.commit('模块名/xxx',额外参数)
- 通过
mapActions
映射
默认根级别的映射mapActions(['xxx'])
子模块的映射mapActions('模块名',['xxx'])
-需要开启命名空间