Vuex的概述
什么是vuex
Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据共享
Vuex管理数据的优点
- A.能够在vuex中集中管理共享的数据,便于开发和后期进行维护
- B.能够高效的实现组件之间的数据共享,提高开发效率
- C.存储在vuex中的数据是响应式的,当数据发生改变时,页面中的数据也会同步更新
Vuex的基本使用步骤
1. 安装
npm i vuex --save
2. 在src文件目录下新建store>index.js文件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store();
export default store;
// vue3中使用
import { createStore } from 'vuex'
import cart from './modules/cart'
import user from './modules/user'
import category from './modules/category'
// 使用第三方插件让vuex持久化 npm i vuex-persistedstate
import createPersistedstate from 'vuex-persistedstate'
export default createStore({
// 数据
state: {},
// 改数据函数
mutations: {},
// 请求数据函数
actions: {},
// 分模块
modules: {
user,
cart,
category
},
// vuex的计算属性
getters: {},
// 配置项
plugins: [
createPersistedstate({
// 保存在本地的名字(key)
key: 'erabbit-client-pc-store',
// 需要保存的模块
paths: ['user', 'cart']
})
// vue3中的调试工具不支持查看vuex 所以通过内置api在控制台打印
// createLogger()
]
})
3. 入口文件里面引入store,然后再全局注入
import store from './store'//引入store
new Vue({
el: '#app',
router,
store,//使用store
template: '<App/>',
components: { App }
})
// vue3
import store from './store'
createApp(App).use(store).use(router).use(UI).use(ElementPlus).mount('#app')
4.使用
- 在state中定义数据
Vue.use(Vuex)
const store = new Vuex.Store({
state:{
count:1
}
})
- Getter相当于vue中的computed计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,Getters 可以用于监听、state中的值的变化,返回计算后的结果
getters:{
getCount:state=>{
return state.count+1
}
- 给action注册事件处理函数,当这个函数被触发时候,将状态提交到mutations中处理。actions里面自定义的函数接收一个context参数和要变化的形参
actions:{
addFun(context,n){
context.commit('add',n)
} ,
removeFun(context){
context.commit("remove")
}
}
- mutations是一个对象里。面的方法 都是同步事务,是更改state初始状态的唯一合法方法,具体的用法就是给里面的方法传入参数state或额外的参数
mutations:{
add(state,n){
state.count = state.count+n
},
remove(){
state.count=state.count-1
}
},
-
dispatch:含有异步操作,例如向后台提交数据,写法: this.$store.dispatch('action方法名',值)
-
commit:同步操作,写法:this.$store.commit('mutations方法名',值)
export defult{
data(){
return{
mag:'aaa'
}
},
methods:{
addCount(){
this.$store.commit('add')
},
reoveCount:function(){
this.$store.commit('remove')
},
addFun(){
let n =2;
this.$store.dispatch('addFun',n)
},
removeFun(){
this.$store.dispatch('removeFun')
}
}
}
5. Vuex持久化
- 在开发的过程中,像用户信息(名字,头像,token)需要vuex中存储且需要本地存储。
- 再例如,购物车如果需要未登录状态下也支持,如果管理在vuex中页需要存储在本地。
- 我们需要category模块存储分类信息,但是分类信息不需要持久化。
- 安装一个vuex的插件vuex-persistedstate来支持vuex的状态持久化
npm i vuex-persistedstate
import { createStore } from 'vuex'
+import createPersistedstate from 'vuex-persistedstate'
import user from './modules/user'
import cart from './modules/cart'
import cart from './modules/category'
export default createStore({
modules: {
user,
cart,
category
},
+ plugins: [
+ createPersistedstate({
+ key: 'erabbit-client-pc-store',
+ paths: ['user', 'cart']
+ })
+ ]
})
- ===> 默认是存储在localStorage中
- ===> key是存储数据的键名
- ===> paths是存储state中的那些数据,如果是模块下具体的数据需要加上模块名称,如user.token
- ===> 修改state后触发才可以看到本地存储数据的的变化。
Vuex的核心特性
State
State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储
在组件中访问State的方式:
1).this.$store.state.全局数据名称 如:this.$store.state.count
<!-- vue3使用根模块state的数据 -->
<p>{{$store.state.username}}</p>
2).先按需导入mapState函数: import { mapState } from 'vuex'
然后数据映射为计算属性: computed:{ ...mapState(['全局数据名称']) }
<!-- vue3 -->
import { useStore } from 'vuex'
const store = useStore()
// 1. 使用根模块state的数据
console.log(store.state.username)
// 2. 使用根模块getters的数据
console.log(store.getters.newName)
// 3. 提交根模块mutations函数
// store.commit('updateName')
// 4. 调用根模块actions函数
store.dispatch('updateName')
<template>
<div>APP组件</div>
<ul>
<li v-for="item in $store.getters.boys" :key="item.id">{{item.name}}</li>
</ul>
<!-- 使用模块A的username -->
<p>A的username --- {{$store.state.a.username}}</p>
<p>A的changeName --- {{$store.getters.changeName}}</p>
<hr>
<p>B的username --- {{$store.state.b.username}}</p>
<p>B的changeName --- {{$store.getters['b/changeName']}}</p>
<button @click="$store.commit('b/update')">修改username</button>
<button @click="$store.dispatch('b/update')">异步修改username</button>
</template>
Mutation
Mutation用于修改变更$store中的数据,只能处理同步数据。不能处理异步数据,会导致vue调试器的显示出错。
- 使用方式第一种
打开store.js文件,在mutations中添加代码如下
mutations: {
add(state,step){
//第一个形参永远都是state也就是$state对象
//第二个形参是调用add时传递的参数
state.count+=step;
}
}
然后在Addition.vue中给按钮添加事件代码如下:
<button @click="Add">+1</button>
methods:{
Add(){
//使用commit函数调用mutations中的对应函数,
//第一个参数就是我们要调用的mutations中的函数名
//第二个参数就是传递给add函数的参数
this.$store.commit('add',10)
}
}
- 使用mutations的第二种方式:
import { mapMutations } from 'vuex'
methods:{
...mapMutations(['add'])
}
import { mapState,mapMutations } from 'vuex'
export default {
data() {
return {}
},
methods:{
//获得mapMutations映射的sub函数
...mapMutations(['sub']),
//当点击按钮时触发Sub函数
Sub(){
//调用sub函数完成对数据的操作
this.sub(10);
}
},
computed:{
...mapState(['count'])
}
}
Action
在vuex中我们可以使用Action来执行异步操作。
获取异步数据,调用Mutation同时将数据交给Mutation
- 操作步骤如下:
打开store.js文件,修改Action,如下:
actions: {
addAsync(context,step){
setTimeout(()=>{
context.commit('add',step);
},2000)
}
}
然后在Addition.vue中给按钮添加事件代码如下
<button @click="AddAsync">...+1</button>
methods:{
AddAsync(){
this.$store.dispatch('addAsync',5)
}
}
- 第二种方式:
import { mapActions } from 'vuex'
methods:{
...mapMutations(['subAsync'])
}
import { mapState,mapMutations,mapActions } from 'vuex'
export default {
data() {
return {}
},
methods:{
//获得mapMutations映射的sub函数
...mapMutations(['sub']),
//当点击按钮时触发Sub函数
Sub(){
//调用sub函数完成对数据的操作
this.sub(10);
},
//获得mapActions映射的addAsync函数
...mapActions(['subAsync']),
asyncSub(){
this.subAsync(5);
}
},
computed:{
...mapState(['count'])
}
}
Getter
Getter用于对Store中的数据进行加工处理形成新的数据 它只会包装Store中保存的数据,并不会修改Store中保存的数据,当Store中的数据发生变化时,Getter生成的内容也会随之变化
打开store/index.js文件,添加getters,如下:
export default new Vuex.Store({
.......
getters:{
//添加了一个showNum的属性
showNum : state =>{
return '最新的count值为:'+state.count;
}
}
})
然后打开Addition.vue中,添加插值表达式使用getters
或者也可以在Addition.vue中,导入mapGetters,并将之映射为计算属性
import { mapGetters } from 'vuex'
computed:{
...mapGetters(['showNum'])
}
Module
当项目变得越来越大的时候,Vuex会变得越来越难以维护由此,又有了Vuex的模块化
- 定义两个模块 user 和 setting
// 原始方法获取
<template>
<div>
<div>用户token {{ $store.state.user.token }}</div>
<div>网站名称 {{ $store.state.setting.name }}</div>
</div>
</template>
请注意: 此时要获取子模块的状态 需要通过 $store.state.模块名称.属性名 来获取
// 这个getters是根级别的getters哦
getters: {
token: state => state.user.token,
name: state => state.setting.name
}
通过mapGetters引用
computed: {
...mapGetters(['token', 'name'])
}
- 如果我们想保证内部模块的高封闭性,我们可以采用namespaced来进行设置
// 与模块内的state ,action等同级
namespaced: true,
- 直接调用-带上模块的属性名路径
test () {
this.$store.dispatch('user/updateToken') // 直接调用方法
}
- 辅助函数-带上模块的属性名路径
methods: {
...mapMutations(['user/updateToken']),
test () {
this['user/updateToken']()
}
}
<button @click="test">修改token</button>
- createNamespacedHelpers 创建基于某个命名空间辅助函
import { mapGetters, createNamespacedHelpers } from 'vuex'
const { mapMutations } = createNamespacedHelpers('user')
<button @click="updateToken">修改token2</button>
结论
- 修改state状态必须通过mutations
- mutations只能执行同步代码,类似ajax,定时器之类的代码不能在mutations中执行
- 执行异步代码,要通过actions,然后将数据提交给mutations才可以完成
- state的状态即共享数据可以在组件中引用
- 组件中可以调用action