核心概念

在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

state

vuex状态管理对象,作为一个“唯一数据源 (SSOT (opens new window))”而存在。组件通过computed计算属性访问

  1. computed: {
  2. count () {
  3. return this.$store.state.count
  4. }

actions

值为一个对象,包含多个响应用户动作的回调函数;通过commit()来触发mutation中函数的调用,间接更新state

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.statecontext.getters 来获取 state 和 getters。但不是store本身

mutations

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

  1. const store = new Vuex.Store({
  2. state: {
  3. count: 1
  4. },
  5. mutations: {
  6. increment (state) {
  7. // 变更状态
  8. state.count++
  9. }
  10. }
  11. })
  1. //组件使用
  2. store.commit('increment')

你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)

  1. // ...
  2. mutations: {
  3. increment (state, n) {
  4. state.count += n
  5. }
  6. }
  7. store.commit('increment', 10)

getters

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

Getter 接受 state 作为其第一个参数:

  1. const store = new Vuex.Store({
  2. state: {
  3. todos: [
  4. { id: 1, text: '...', done: true },
  5. { id: 2, text: '...', done: false }
  6. ]
  7. },
  8. getters: {
  9. doneTodos(state) {
  10. return state.todos.filter(todo => todo.done)
  11. }
  12. }
  13. })

组件访问

Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:

  1. store.getters.doneTodos
  2. // [{ id: 1, text: '...', done: true }]

简单使用

1、安装

  1. npm install vuex

2、main.js引入

  1. //引入store
  2. import store from './store'
  3. new Vue({
  4. el:'#app',
  5. render: h => h(App),
  6. store
  7. })

3、创建配置文件:src/store/index.js

  1. //该文件用于创建Vuex中最为核心的store
  2. import Vue from 'vue'
  3. //引入Vuex
  4. import Vuex from 'vuex'
  5. //应用Vuex插件
  6. Vue.use(Vuex)
  7. //准备actions——用于响应组件中的动作
  8. const actions = {
  9. /* jia(context,value){
  10. console.log('actions中的jia被调用了')
  11. context.commit('JIA',value)
  12. },
  13. jian(context,value){
  14. console.log('actions中的jian被调用了')
  15. context.commit('JIAN',value)
  16. }, */
  17. jiaOdd(context,value){
  18. console.log('actions中的jiaOdd被调用了')
  19. if(context.state.sum % 2){
  20. context.commit('JIA',value)
  21. }
  22. },
  23. jiaWait(context,value){
  24. console.log('actions中的jiaWait被调用了')
  25. setTimeout(()=>{
  26. context.commit('JIA',value)
  27. },500)
  28. }
  29. }
  30. //准备mutations——用于操作数据(state)
  31. const mutations = {
  32. JIA(state,value){
  33. console.log('mutations中的JIA被调用了')
  34. state.sum += value
  35. },
  36. JIAN(state,value){
  37. console.log('mutations中的JIAN被调用了')
  38. state.sum -= value
  39. }
  40. }
  41. //准备state——用于存储数据
  42. const state = {
  43. sum:0 //当前的和
  44. }
  45. //准备getters——用于将state中的数据进行加工
  46. const getters = {
  47. bigSum(state){
  48. return state.sum*10
  49. }
  50. }
  51. //创建并暴露store
  52. export default new Vuex.Store({
  53. actions,
  54. mutations,
  55. state,
  56. getters
  57. })

4、组件使用

  1. <template>
  2. <div>
  3. <h1>当前求和为:{{$store.state.sum}}</h1>
  4. <h3>当前求和放大10倍为:{{$store.getters.bigSum}}</h3>
  5. <select v-model.number="n">
  6. <option value="1">1</option>
  7. <option value="2">2</option>
  8. <option value="3">3</option>
  9. </select>
  10. <button @click="increment">+</button>
  11. <button @click="decrement">-</button>
  12. <button @click="incrementOdd">当前求和为奇数再加</button>
  13. <button @click="incrementWait">等一等再加</button>
  14. </div>
  15. </template>
  16. <script>
  17. export default {
  18. name:'Count',
  19. data() {
  20. return {
  21. n:1, //用户选择的数字
  22. }
  23. },
  24. methods: {
  25. increment(){
  26. //逻辑简单的情况下可跳过actionscommit给mutations直接操作state数据
  27. this.$store.commit('JIA',this.n)
  28. },
  29. decrement(){
  30. this.$store.commit('JIAN',this.n)
  31. },
  32. incrementOdd(){
  33. this.$store.dispatch('jiaOdd',this.n)
  34. },
  35. incrementWait(){
  36. this.$store.dispatch('jiaWait',this.n)
  37. },
  38. },
  39. mounted() {
  40. console.log('Count',this.$store)
  41. },
  42. }
  43. </script>
  44. <style lang="css">
  45. button{
  46. margin-left: 5px;
  47. }
  48. </style>

mapState、mapGetters、mapActions、mapMutations

当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性

  1. const state = {
  2. sum:0, //当前的和
  3. name:'',
  4. sex:''
  5. }
  6. const getters = {
  7. bigSum(state){
  8. return state.sum*10
  9. }
  10. }
  1. computed:{
  2. //借助mapState生成计算属性,从state中读取数据。(数组写法)
  3. ...mapState(['sum','name','sex']),
  4. //相当于
  5. sum(){
  6. return this.$store.state.sum
  7. }
  8. ...
  9. //借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
  10. ...mapGetters(['bigSum'])
  11. }
  1. methods: {
  2. //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
  3. ...mapMutations({increment:'JIA',decrement:'JIAN'}),
  4. //相当于
  5. increment(){
  6. this.$store.commit('JIA',this.n)
  7. },
  8. decrement(){
  9. this.$store.commit('JIAN',this.n)
  10. },
  11. //数组写法
  12. ...mapMutations(['JIA','JIAN']),
  13. /* ************************************************* */
  14. //借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
  15. ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
  16. //相当于
  17. incrementOdd(){
  18. this.$store.dispatch('jiaOdd',this.n)
  19. },
  20. incrementWait(){
  21. this.$store.dispatch('jiaWait',this.n)
  22. },
  23. //数组写法
  24. ...mapActions(['jiaOdd','jiaWait'])
  25. },
  • 在计算属性中定义后,模板中就可以直接访问变量,不需要再带上$store.state$store.getters
  • mapActionsmapMutations无法传参,如果要传参数,需要在方法调用出定义参数
  1. <template>
  2. <div>
  3. <h1>当前求和为:{{sum}}</h1>
  4. <h3>当前求和放大10倍为:{{bigSum}}</h3>
  5. <select v-model.number="n">
  6. <option value="1">1</option>
  7. <option value="2">2</option>
  8. <option value="3">3</option>
  9. </select>
  10. <!--在此处传递参数-->
  11. <button @click="increment(n)">+</button>
  12. <button @click="decrement(n)">-</button>
  13. <button @click="jiaWait(n)">等一等再加</button>
  14. </div>
  15. </template>
  16. <script>
  17. import {mapActions, mapGetters, mapMutations, mapState} from "vuex";
  18. export default {
  19. name:'count',
  20. data() {
  21. return {
  22. n:1, //用户选择的数字
  23. }
  24. },
  25. methods: {
  26. ...mapMutations({increment: 'JIA',decrement: 'JIAN'}),
  27. ...mapActions(['jiaWait']),
  28. },
  29. mounted() {
  30. console.log('Count',this.$store)
  31. },
  32. computed:{
  33. ...mapState(['sum']),
  34. ...mapGetters(['bigSum'])
  35. }
  36. }
  37. </script>
  38. <style lang="css">
  39. button{
  40. margin-left: 5px;
  41. }
  42. </style>

模块化

如果vuex只有一个state,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割

配置

在store文件加下创建多个store配置文件,名字自定义

  1. //person.js 人员管理相关的配置
  2. export default {
  3. namespaced:true, //命名空间需设置为true
  4. actions:{
  5. addPersonWang(context,value){
  6. if(value.name.indexOf('王') === 0){
  7. context.commit('ADD_PERSON',value)
  8. }else{
  9. alert('添加的人必须姓王!')
  10. }
  11. },
  12. addPersonServer(context){
  13. axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
  14. response => {
  15. context.commit('ADD_PERSON',{id:nanoid(),name:response.data})
  16. },
  17. error => {
  18. alert(error.message)
  19. }
  20. )
  21. }
  22. },
  23. mutations:{
  24. ADD_PERSON(state,value){
  25. console.log('mutations中的ADD_PERSON被调用了')
  26. state.personList.unshift(value)
  27. }
  28. },
  29. state:{
  30. personList:[
  31. {id:'001',name:'张三'}
  32. ]
  33. },
  34. getters:{
  35. firstPersonName(state){
  36. return state.personList[0].name
  37. }
  38. },
  39. }
  1. //count.js 求和相关的配置
  2. export default {
  3. namespaced:true, //命名空间需设置为true
  4. actions:{
  5. jiaOdd(context,value){
  6. console.log('actions中的jiaOdd被调用了')
  7. if(context.state.sum % 2){
  8. context.commit('JIA',value)
  9. }
  10. },
  11. jiaWait(context,value){
  12. console.log('actions中的jiaWait被调用了')
  13. setTimeout(()=>{
  14. context.commit('JIA',value)
  15. },500)
  16. }
  17. },
  18. mutations:{
  19. JIA(state,value){
  20. console.log('mutations中的JIA被调用了')
  21. state.sum += value
  22. },
  23. JIAN(state,value){
  24. console.log('mutations中的JIAN被调用了')
  25. state.sum -= value
  26. },
  27. },
  28. state:{
  29. sum:0, //当前的和
  30. school:'尚硅谷',
  31. subject:'前端',
  32. },
  33. getters:{
  34. bigSum(state){
  35. return state.sum*10
  36. }
  37. },
  38. }
  1. //该文件用于创建Vuex中最为核心的store
  2. import Vue from 'vue'
  3. //引入Vuex
  4. import Vuex from 'vuex'
  5. import countOptions from './count'
  6. import personOptions from './person'
  7. //应用Vuex插件
  8. Vue.use(Vuex)
  9. //创建并暴露store
  10. export default new Vuex.Store({
  11. modules:{
  12. countAbout:countOptions,
  13. personAbout:personOptions
  14. }
  15. })

组件使用

  1. <!--person.vue-->
  2. <template>
  3. <div>
  4. <h1>人员列表</h1>
  5. <h3 style="color:red">Count组件求和为:{{sum}}</h3>
  6. <h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
  7. <input type="text" placeholder="请输入名字" v-model="name">
  8. <button @click="add">添加</button>
  9. <button @click="addWang">添加一个姓王的人</button>
  10. <button @click="addPersonServer">添加一个人,名字随机</button>
  11. <ul>
  12. <li v-for="p in personList" :key="p.id">{{p.name}}</li>
  13. </ul>
  14. </div>
  15. </template>
  16. <script>
  17. import {nanoid} from 'nanoid'
  18. export default {
  19. name:'Person',
  20. data() {
  21. return {
  22. name:''
  23. }
  24. },
  25. computed:{
  26. personList(){
  27. return this.$store.state.personAbout.personList
  28. },
  29. sum(){
  30. return this.$store.state.countAbout.sum
  31. },
  32. firstPersonName(){
  33. //官方规定获取指定模块的getters
  34. return this.$store.getters['personAbout/firstPersonName']
  35. }
  36. },
  37. methods: {
  38. add(){
  39. const personObj = {id:nanoid(),name:this.name}
  40. this.$store.commit('personAbout/ADD_PERSON',personObj)
  41. this.name = ''
  42. },
  43. addWang(){
  44. const personObj = {id:nanoid(),name:this.name}
  45. this.$store.dispatch('personAbout/addPersonWang',personObj)
  46. this.name = ''
  47. },
  48. addPersonServer(){
  49. this.$store.dispatch('personAbout/addPersonServer')
  50. }
  51. },
  52. }
  53. </script>
  1. <template>
  2. <div>
  3. <h1>当前求和为:{{sum}}</h1>
  4. <h3>当前求和放大10倍为:{{bigSum}}</h3>
  5. <h3>我在{{school}},学习{{subject}}</h3>
  6. <h3 style="color:red">Person组件的总人数是:{{personList.length}}</h3>
  7. <select v-model.number="n">
  8. <option value="1">1</option>
  9. <option value="2">2</option>
  10. <option value="3">3</option>
  11. </select>
  12. <button @click="increment(n)">+</button>
  13. <button @click="decrement(n)">-</button>
  14. <button @click="incrementOdd(n)">当前求和为奇数再加</button>
  15. <button @click="incrementWait(n)">等一等再加</button>
  16. </div>
  17. </template>
  18. <script>
  19. import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
  20. export default {
  21. name:'Count',
  22. data() {
  23. return {
  24. n:1, //用户选择的数字
  25. }
  26. },
  27. computed:{
  28. //借助mapState生成计算属性,从state中读取数据。(数组写法)
  29. ...mapState('countAbout',['sum','school','subject']),
  30. ...mapState('personAbout',['personList']),
  31. //借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
  32. ...mapGetters('countAbout',['bigSum'])
  33. },
  34. methods: {
  35. //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
  36. ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
  37. //借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(对象写法)
  38. ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
  39. },
  40. mounted() {
  41. console.log(this.$store)
  42. },
  43. }
  44. </script>
  45. <style lang="css">
  46. button{
  47. margin-left: 5px;
  48. }
  49. </style>

Vuex状态管理——任意组件间通信的更多相关文章

  1. vuejs组件交互 - 03 - vuex状态管理实现组件交互

    组件交互模式的使用场景 简单应用直接使用props down,event up的模式就可以了 小型应用使用事件中心模式即可 中大型应用使用vuex的状态管理模式 vuex 包含要管理的应用数据和更新数 ...

  2. 前端Vue框架-vuex状态管理详解

    新人报道!多多关照-多提宝贵意见 谢谢- vuex理解 采用集中式存储管理模式.用来管理组件的状态,并以自定义规则去观测实时监听值得变化. 状态模式管理理解 属性 理解 state 驱动应用的数据源 ...

  3. 09:vuex组件间通信

    1.1 vuex简介 官网:https://vuex.vuejs.org/zh/guide/ 参考博客:https://www.cnblogs.com/first-time/p/6815036.htm ...

  4. Vue2不使用Vuex如何实现兄弟组件间的通信

    在一些正规的大型项目的企业级开发过程中我们一般会引入Vuex来对Vue所有组件进行状态管理,可以轻松实现各组件间的通信.但是有时候做做自己的小项目,没有必要使用Vuex时,如何简单的实现组件间的通信? ...

  5. vue 通信:父子通信、兄弟通信、跨多层通信、vuex状态管理

    之前简单做了一次vue通信方法的培训,在此记录一下培训的内容. 关于vue通信,大家最先想到的方法应该是props.ref.$emit.$parent,还有vuex,因为这也是我在项目中最常用到的方法 ...

  6. Vuex 状态管理的工作原理

    Vuex 状态管理的工作原理 为什么要使用 Vuex 当我们使用 Vue.js 来开发一个单页应用时,经常会遇到一些组件间共享的数据或状态,或是需要通过 props 深层传递的一些数据.在应用规模较小 ...

  7. 聊聊Vue.js组件间通信的几种姿势

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:https://github.com/a ...

  8. vuex状态管理

    msvue组件间通信时,若需要改变多组件间共用状态的值.通过简单的组件间传值就会遇到问题.如:子组件只能接收但改变不了父组件的值.由此,vuex的出现就是用作各组件间的状态管理. 简单实例:vuex的 ...

  9. python 全栈开发,Day91(Vue实例的生命周期,组件间通信之中央事件总线bus,Vue Router,vue-cli 工具)

    昨日内容回顾 0. 组件注意事项!!! data属性必须是一个函数! 1. 注册全局组件 Vue.component('组件名',{ template: `` }) var app = new Vue ...

随机推荐

  1. python学习笔记(十五)-unittest单元测试的一个框架

    unittest 单元测试的一个框架什么框架 一堆工具的集合. TestCase TestSuite 测试套件,多个用例在一起 TestLoader是用来加载TestCase到TestSuite中的 ...

  2. Python项目生成requirements.txt文件之pipreqs的使用

    生成requirements.txt时使用pip freeze > requirements.txt会将环境下所有的安装包都进行生成,再进行安装的时候会全部安装很多没有的包.耗时耗力其实是不可取 ...

  3. VS2013的switch case缩进问题

    原来的   更改设置   改完后    

  4. HTML 网页开发、CSS 基础语法——十一. CSS常用样式

    文字三属性 1.颜色color 2.字体font-family ① 常用字体 常用的中文字体: 宋体  SimSum 微软雅黑 Microsoft YaHei 常用的英文字体: 如果不设置字体属性,不 ...

  5. Spring面试复习整理

    Spring Spring核心分为三方面: 控制反转(IoC): 就是将创建对象的权利交给框架处理/控制,不需要人为创建,有效降低代码的耦合度,降低了开发成本. 依赖注入(DI): 容器动态地将将某种 ...

  6. redux搭配react-redux进行跨组件通信开发

    Redux API 作用 createStore 用于创建一个store对象 bindActionCreators 用于简化操作,不用开发者手动触发dispatch React-redux API 作 ...

  7. Springboot中使用Redisson实现分布式锁

    1. 概述 老话说的好:便宜没好货,有价值的商品,即使再贵,也有人会买. 言归正传,今天继续讨论有关"锁"的话题,synchronized 和 ReentrantLock 大家应该 ...

  8. JVM学习笔记——堆

    堆 Heap 一个 JVM 只有一个堆,堆也是 Java 内存管理的核心区域.在 JVM 启动时堆被创建,同时大小在启动时已设定好,堆是 JVM 管理最大的一块内存空间,其大小可以调节. 堆的内存空间 ...

  9. 从零入门 Serverless | Serverless 应用如何管理日志 & 持久化数据

    作者 | 竞霄 阿里巴巴开发工程师 本文整理自<Serverless 技术公开课>,关注"Serverless"公众号,回复"入门",即可获取 Se ...

  10. k8s调度器介绍(调度框架版本)

    从一个pod的创建开始 由kubectl解析创建pod的yaml,发送创建pod请求到APIServer. APIServer首先做权限认证,然后检查信息并把数据存储到ETCD里,创建deployme ...