Vue中的Vuex

发布时间 2023-11-21 22:43:29作者: 自学Java笔记本

概述

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
对于组件间的通信方式而言,vuex也是一个可以进行任意组件通信的方法。

使用场景:

  • 某个状态在很多组件来使用(个人信息)
  • 多个组件共同维护一份数据(购物车)

优势:

  • 共同维护一份数据,数据集中化管理
  • 响应式变化
  • 操作简洁(vuex提供了一些辅助函数)

image

组件间共享数据的方式

  • 父向子传值:v-bind属性绑定
  • 子向父传值:v-on事件绑定
  • 兄弟组件之间共享数据:EventBus
  • $on 接收数据的组件
  • $emit 发送数据的组件

Demo案例

image

当组件变化时对应的其他组件的值也会发生变化。说白了,操作的是共享数据,一旦发生变化,能够影响到所有使用到它的值。

创建一个空仓库

  • 目标:安装vuex插件,初始化一个空仓库
    npm install vuex --save

  • 新建 store/index.js 专门存放vuex

  • Vue.use(Vuex)创建仓库 new Vuex.Store()

  • 在main.js中导入挂载到Vue实例上

image

核心概念-state状态

目标:明确如何给仓库 提供 数据,如何使用仓库的数据

提供数据

state 提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储,在state对象中可以添加我们要共享的数据。
image

使用数据

  • 通过store直接访问
获取store:
1.this.$store
2.import store from './store'

模板中:{{$store.state.xxx}}
组件逻辑中:this.$store.state.xxx
js模块中: store.state.xxx
  • 使用计算属性
    将vuex仓库中的数据,通过计算属性的方式封装起来,当调用的时候只需要写计算属性的名称,这样方便同时简洁

image

  • 通过辅助函数
    使用mapState是辅助函数,帮助我们把store中的数据自动映射到组件的计算属性中

使用步骤:

  • 导入mapState---> import {mapState} from 'vuex'
  • 数组方式引入state---> mapState(['count'])
  • 展开运算符映射

image

核心概念-mutations

目标:明确vuex 同样遵循单向数据流,组件中不能直接修改仓库的数据

在这里于prop一致,父组件传递个子组件的数据, 子组件不能直接修改,子组件需要给父组件传递信息让父组件去修改,而vuex一样,对于组件来说,需要修改数据,需要通知vuex。此时可以用到mutations

  • 定义mutations对象,对象中存放修改state的方法
    image

  • 组件中提交调用mutations
    this.$store.commit('addCount')
    image

太麻烦了对于上诉使用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)
    }
  }

注意:在传参的过程中,只能传递一个参数,要想传递多个参数,请用对象的形式。
例如:
image

辅助函数:mapMutations

mapMutationsmapState 很像,它是把位于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

需求:一秒钟后在将数据改变,例如:
image

实现步骤:

  • 在仓库中提供一个 action方法,该方法用一个定时最后再去执行mutations中的方法。
  • 页面中通过this.$store.dispatch('action的方法',参数)调用
    image

对于actions来说,一般的场景使用就是发起请求。

辅助函数-mapActions

mapActions是把位于 actions中的方法提取出来,映射到组件methods中

它跟 mapState、mapMutations是一样的,都是将仓库中的数据或者方法,映射到组件中从而简化代码。
image

核心概念-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}}
    

image

核心概念-模块 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
	}
})

image

组件使用:
尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的state中,属性名就是模块名

  • 直接通过模块名访问 $store.state.模块名.xxx
  • 通过mapState映射
    默认根级别的映射mapState(['xxx'])
    子模块的映射mapState('模块名',['xxx']) -需要开启命名空间
    image

使用模块中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']) -需要开启命名空间
    image

调用子模块 actions

  • 直接通过store调用$store.commit('模块名/xxx',额外参数)
  • 通过mapActions映射
    默认根级别的映射mapActions(['xxx'])
    子模块的映射mapActions('模块名',['xxx']) -需要开启命名空间