一、vuex
1. 概念
Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
① 能够在 vuex 中集中管理共享的数据,易于开发和后期维护
② 能够高效地实现组件之间的数据共享,提高开发效率
③ 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步
一般情况下,只有组件之间共享的数据,才有必要存储到 vuex 中;对于组件中的私有数据,依旧存储在组件自身的 data 中即可。
2. 不使用脚手架,在项目中配置vuex
(1)安装 vuex 依赖包
npm install vuex --save
(2)在 store.js 文件中导入 vue 和 vuex。全局注册vuex。
import Vue from 'vue'
import Vuex from 'vuex'
全局注册vuex: Vue.use(Vuex)
(3) 在 store.js 文件中创建 store 对象
const store = new Vuex.Store({
// state 中存放的就是全局共享的数据
state: { count: 0 }
})
(4)在main.js中导入store.js ,并将 store 对象挂载到 vue 实例中
new Vue({
el: '#app',
render: h => h(app),
router,
// 将创建的共享数据对象,挂载到 Vue 实例中
// 所有的组件,就可以直接从 store 中获取全局的数据了
store
})
二、 vuex的核心属性
注意:
(1)在 组件 中可以用 $store 调用store中的数据和方法。
(2)在普通的 js文件 中需要用 import 导入 vuex文件,才能使用其中的数据。
(3)用脚手架创建项目后,在vuex文件中创建vuex的实例对象store。
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {},
modules: {
// 子模块users
users: {
namespaced: true
state: {},
mutations: {},
actions: {},
getters: {}
},
// 子模块settings
settings: {
namespaced: true
state: {},
mutations: {},
actions: {},
getters: {}
}
}
})
1. state
所有 共享的数据 都要统一放到 vuex的实例对象store 的 state 中进行存储。
(1)将数据存放到 state 中。
(2)在组件中调用 state 数据的第一种方法:直接在组件中获取state数据
this.$store.state.数据名称
(3)在组件中调用 state 数据的第二种方法:将state数据映射为本组件的计算属性。
① 首先在组件中导入vuex 提供的 mapState 函数
import { mapState } from 'vuex'
② 使用mapState方法将 state 中的数据映射为本组件的 计算属性
export default {
computed: {
...mapState(['数据名称'])
}
}
2. mutations
只有 mutations 中的方法,才能真正操作 state 中的数据。
(1)在 mutations 中定义方法,每个方法的第一个参数都是 state。通过参数state,可以得到state 中的数据进行操作。第二个参数往后都是自定义参数。
mutations: {
addOne (state, tempNum) {
state.count += tempNum
},
},
(2)在组件中操作 state 数据的第一种方法:直接在组件中获取mutations方法。
this.$store.commit('mutations方法名称', 自定义参数)
注意:如果需要传递多个参数,请使用对象或者数组一次性传递过来。
(3)在组件中操作 state 数据的第二种方法:将mutations方法映射为本组件的方法。
① 首先在组件中导入vuex 提供的 mapMutations 函数
import {mapMutations } from 'vuex'
② 使用mapMutations函数将 mutations 中的方法映射为本组件的方法。
methods: {
...mapMutations([ 'mutations方法名' ]),
}
3. action
- 异步操作都存放在 action 中。
- 但是,只有 mutations 才能真正操作state 数据。
- 所以,action 中的异步函数要调用 mutations 中的方法,来实现异步地操作state数据。
- actions中的方法大多用 async 标记成异步函数了,组件调用时要用async 和 await 标记。
(1) 在 action 中定义异步函数,并在函数内部调用 mutations 中的方法。
每个异步函数的第一个参数都是 context,通过 context.commit( 'mutations方法名',自定义参数) 可以调用 mutations 中的方法。
actions: {
addAsync (context, tempNum) {
setTimeout(() => {
context.commit(' addOne ', tempNum)
}, 1000)
},
},
(2)在组件中异步地操作state数据的第一种方法:直接在组件中调用action的异步函数。
this.$store.dispatch('action方法名', 自定义参数)
(3)在组件中异步地操作state数据的第二种方法:将action方法映射为本组件的方法。
① 首先在组件中导入vuex 提供的 mapActions 函数
import {mapActions } from 'vuex'
② 使用mapActions函数将 actions 中的方法映射为本组件的方法
methods: {
...mapActions([ 'mutations方法名' ]),
}
4. getters
① vuex中的getters 与 vue中的 计算属性 类似。
② 除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters.
③ 在 getters 中定义方法,每个方法的 第一个参数都是 state。
④ getters中的函数必须有返回值。getters函数在组件中被当做 state数据 使用。
getters: {
filterList (state) {
return state.list.filter(item => item > 5)
},
},
(1)直接在组件中使用vuex中的getters
this.$store.getters.方法名
(2)将vuex的getters映射为组件的计算属性
① 在组件中导入vuex提供的 mapGetters 放法
import {mapGetteers } from 'vuex'
② 利用mapGetters方法,将getters映射为组件的计算属性。
computed: {
...mapGetters(['方法名称'])
}
三、vuex的模块化
vuex中的第五个 核心属性modules,可以创建子模块vuex。
1. 在组件中使用vuex子模块的 state 数据
方法一: 直接在组件中调用
this.$store.state.vuex子模块名称.数据名称
<div>{{$store.state.users.name}}</div>
方法二:将vuex子模块中的数据,包装为全局getters。组件调用全局的getters。
全局getters属性:
getters:{
自定义名称:(state)=>{ return state.子模块名称.数据名称 }
}
getters: {
usersName: (state) => {
return state.users.name
}
}
方法三:在组件中使用mapState方法,映射为组件的计算属性。
computed:{ ...mapState("vuex模块名称",[])}
注:uniapp小程序中学的
computed:{
...mapState('Cart',['name'])
},
2.在组件中调用vuex子模块的 mutations方法
① 默认情况下,子模块的mutations方法被注册到了全局的vuex上。组件可以通过this.$store.commit.方法名 调用。
② 但这不符合模块化的封装,所以,要给每个vuex子模块添加属性:namespaced:true
方法一:直接在组件中调用--带上子模块名称
this.$store.commit( "vuex子模块名称 / 方法名称" ,实参)
this.$store.commit('users/changeName', '马冬梅')
方法二:mapMutations函数映射--方法名前面要加子模块名称。
methods: {
...mapMutations(['子模块名称 / 方法名']),
test () {
this['子模块名称 / 方法名'] ()
}
}
也可以写成:...mapMutations("子模块名称",["方法名"])
注:uniapp小程序中学的
方法三:使用 createNamespacedHelpers 创建基于某个命名空间辅助函数
import { mapGetters, createNamespacedHelpers } from 'vuex'
const { mapMutations } = createNamespacedHelpers('子模块名称')
组件中添加了这两行代码,就可以在methods中映射指定子模块的mutations方法了。
四、vuex兄弟子模块之间方法的调用
① 上面已经详细说明了如何在 vue组件中调用 vuex的数据和方法。
② 但是,两个添加了namespaced命名空间的 vuex子模块,不能相互使用其中的数据和方法。因为添加了命名空间后,子模块的state、context只能拿到当前模块的数据和方法。
在子模块A的actions中调用子模块B的mutations方法:
context.commit(" 模块名称/mutations方法名称" , [], { root: true })
五、同一子模块的mutations方法的相互调用
理论上来说,使用this.commit('函数 ')即可调用另一个Mutations方法。
但是在开启命名空间的子模块中,使用 this.commit(’ 模块名/函数 ') 的方法来调用。即便是在同一个模块下,Mutations中的其中一个方法回调另一个方法时,也需要用 this.commit(’ 模块名/函数 ') 的方式来调用。
this.commit("子模块名/函数 ")
六、 vuex实际应用
1.该组件使用state数据、mutations方法、actions方法时,都是直接调用。
<template>
<div>
<!-- 组件内使用state中的数据 方法一 -->
<div>vuex中的数据count值为:{{$store.state.count}}</div>
<button @click="handler1">+1</button>
<button @click="handler2">+5</button>
</div>
</template>
<script>
export default {
methods: {
// 组件内操作state中的数据 方法一
handler1 () {
this.$store.commit('addOne', 1)
},
// 组件内异步地操作state中的数据 方法一
handler2 () {
this.$store.dispatch('addAsync', 5)
}
}
}
</script>
<style scoped>
</style>
2.这是vuex文件。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
// 存储公有数据
state: {
count: 0
},
// 存放更改公有数据的方法
mutations: {
// 加一
addOne (state, tempNum) {
state.count += tempNum
},
// 减一
subOne (state, tempNum) {
state.count -= tempNum
}
},
// 存放异步方法
actions: {
// 异步加5
addAsync (context, tempNum) {
setTimeout(() => {
context.commit('addOne', tempNum)
}, 1000)
},
// 异步减5
subAsync (context, tempNum) {
setTimeout(() => {
context.commit('subOne', tempNum)
}, 1000)
}
},
modules: {
}
})
export default store
3.该组件使用state数据、mutations方法、actions方法时,都是映射到本组件内再使用。
<template>
<div>
<div>{{count}}</div>
<button @click="handler1">-1</button>
<button @click="handler2">-5</button>
</div>
</template>
<script>
// 导入 vuex 提供的 【mapState】方法
// 导入 vuex 提供的 【mapMutations】方法
// 导入 vuex 提供的 【mapActions】方法
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
// 组件内使用state数据 方法二
computed: {
...mapState(['count'])
},
methods: {
// 组件内操作state数据 方法二
...mapMutations(['subOne']),
handler1 () {
this.subOne(1)
},
// 组件内异步地操作state数据 方法二
...mapActions(['subAsync']),
handler2 () {
this.subAsync(5)
}
}
}
</script>
<style scoped>
</style>
补充:
- 一个对象调用它的属性时的三种方法:
对象名.属性名
对象名[ "属性名" ]
对象名[ 变量名 ],其中变量的值等于属性名
平常使用变量,用的是变量名;但只要给 变量 加上 [ ],就代表获取变量值。
例如:
var a = 10
console.log({ a: '猜猜a是什么' }) // { a: '猜猜a是什么' }
console.log({ [a]: '猜猜a是什么' }) // { 10: '猜猜a是什么' }
- vuex中的数据响应式
只修改数组或对象的元素、属性,不具有数据的响应式效果。
也就是必须给数组或对象赋值替代,才能在改变数据时让页面也同步变化。