Vue全家桶(三):Vuex状态管理(State、Getters、Mutations、Actions)

news2024/11/15 21:45:38

目录

  • Vuex
    • 1. 理解Vuex
      • 1.1 组件之间共享数据的方式
      • 1.2 Vuex是什么
      • 1.2 什么时候使用Vuex
      • 1.3 Vuex的工作原理图
    • 2 使用Vuex
      • 2.1 搭建Vuex环境
    • 2.2 Vuex基本使用
      • 2.2.1 State
      • 2.2.2 Getters
      • 2.2.3 Mutations
      • 2.2.4 Actions
      • 2.2.5 Modules 模块化+命名空间
    • 3 求和案例
      • 3.1 使用纯vue编写
      • 3.2 使用Vuex编写
        • 3.2.1 原始写法
        • 3.2.2 用mapXXX优化后
        • 3.2.2 多组件共享数据
        • 3.2.3 模块化优化后
    • 4 求和案例2
      • 4.1 props传递值
      • 4.2 Vuex的state传递
      • 4.3 Matuations来修改状态
      • 4.4 Mutations带参数传递修改状态
    • 5 多组件共享数据案例

Vuex

1. 理解Vuex

1.1 组件之间共享数据的方式

父向子传值:v-bind 属性绑定
子向父传值:v-on 事件绑定

兄弟组件之间共享数据: EventBus(事件总线)
$on 接收数据的那个组件
$emit 发送数据的那个组件

1.2 Vuex是什么

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

Vuex Github: https://github.com/vuejs/vuex

  1. 全局事件总线和Vuex对比
    Vuex是什么
    在这里插入图片描述

1.2 什么时候使用Vuex

处理大量的需要在组件间传递的数据,直接定义一个全局的data属性保存就行了。
如果我们的页面比较简单,切记千万不要没事找事引入Vuex,我们使用Vuex是因为项目变得复杂之后,有很多数据需要在父组件、子组件和孙组件之间传递,处理起来很繁琐,于是就需要Vuex这样一个可以对这一部分数据进行统一管理的东西,也是响应式

什么情况需要使用Vuex管理状态在多个组件间共享?

  1. 多个组件依赖于同一状态
  2. 来自不同组件的行为需要变更同一状态

大型项目中组件很多,多个组件中共用的数据
例如:用户的登录状态、用户名称、头像、地理位置信息等
例如:商品的收藏、购物车中的物品。
例如:传递组件之间传递层次太多、不相关组件、公用组件

Vuex有点类似cookie和session,session是用于服务器端共享,cookie是用于浏览器的,Vuex是用于前端组件间共享

1.3 Vuex的工作原理图

在这里插入图片描述

四个核心概念
Vuex 的四个核心概念分别是:

  • The state tree:Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个『唯一数据源(SSOT)』而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
  • Getters:用来从 store 获取 Vue 组件数据。
  • Mutation:事件处理器用来驱动状态的变化。
  • Actions:可以给组件使用的函数,以此用来驱动事件处理器 mutations

Vuex和简单的全局对象是不同的,当Vuex从store中读取状态值的时候,若状态发生了变化,那么相应的组件也会高效的更新。并且,改变store中状态的唯一途径就是提交commit mutations。这样便于我们跟踪每一次状态的变化。只要发生了状态的变化,一定伴随着mutation的提交。

2 使用Vuex

2.1 搭建Vuex环境

  1. 下载安装 Vuex npm i vuex@3
    npm i vuex 是安装最新版本的Vuex
    注意:
  • Vue2中,要用Vuex的3版本
  • Vue3中,要用Vuex的4版本
  1. 创建 src/store/index.js 该文件用于创建Vuex中最为核心的 store

文件目录
在这里插入图片描述
store/index.js

写法一:

import Vue from 'vue'
import Vuex from 'vuex'   //引入Vuex

Vue.use(Vuex)    //应用Vuex
 
//创建并暴露store
export default new Vuex.Store({
  //数据,相当于data
  state: {},
  getters: {},      //里面定义方法,操作state方法
  mutations: {},    // 操作数据State
  actions: {},     //用于响应组件中的动作
  modules: {},    
})

写法二:

import Vue from 'vue'
import Vuex from 'vuex'   //引入Vuex

Vue.use(Vuex)    //应用Vuex
 
 const actions = {}     //用于响应组件中的动作
 const mutations = {}   // 操作数据State
 const state = {}
 const getters= {}   //里面定义方法,操作state方法
 const modules1 = {}
 const modules2 = {}
 
//创建并暴露store
export default new Vuex.Store({
  //数据,相当于data
  state,
  getters,      
  mutations,    
  actions,    
  modules: {
  	modules1,
  	modules2
  }   
})
  1. src/main.js 中创建vm中传入store配置项
    在这里插入图片描述

2.2 Vuex基本使用

Vuex的基本使用
Vuex中一共有五个状态 State、Getter、Mutation、Action、Module

2.2.1 State

提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,相似与data
在vuex中state中定义数据,可以在任何组件中进行调用

import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)
 
export default new Vuex.Store({
  //数据,相当于data
  state: {
    name:"张三",
    age:12,
    sex: '男',
    count:0
  },
})

读取
方法一:在标签中直接使用

<p>{{ $store.state.name }}</p>
<p>{{ $store.state.age}}</p>

方法二:

this.$store.state.全局数据名称

方法三:
从vuex中按需导入mapstate函数

// 1. 从 vuex 中按需导入 mapState 函数
import { mapState } from "vuex";

通过刚才导入的 mapState 函数,将当前组件需要的全局数据,映射为当前组件的 computed 计算属性

// 2. 将全局数据,映射为当前组件的计算属性 
computed: { 
	// 对象写法
	...mapState({name:'name', age:'age', sex:'sex'}) 
	// 数组写法
	...mapState(['name', 'age', 'sex']) 
}

在这里插入图片描述
修改Vuex中的数据

$store.dispatch('action中的方法名',数据)
//或是
$store.commit('mutations中的方法名',数据)

若没有网络请求或其他业务逻辑,组件中也可越过 actions,即不写 dispatch ,直接编
commit

2.2.2 Getters

Getters 用于对 Store 中的数据进行加工处理形成新的数据。

①Getters 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性。
②Store 中数据发生变化,Getters 的数据也会跟着变化。

具体操作类似于前几种
在Vuex中定义:

// 定义 Getters
export default new Vuex.Store({
	state: {
		count: 0
	},
	getters: {
		showNum: state => {
			return '当前最新的数量是【'+ state.count * 10 +'】'
		}
	}
})

在组件中使用:

方法一:在标签中直接使用

<p>{{ $store.getter.name }}</p>
<p>{{ $store.state.age}}</p>

方法二:

this.$store.getters.名称

方法二:
从vuex中按需导入mapGetters 函数

import { mapGetters } from 'vuex'

通过刚才导入的 mapGetters 函数,用于帮助映射 getters中的数据为当前组件的 computed 计算属性

computed: {
	//对象写法
	...mapGetters({showNum:'showNum'})
	//数组写法
	...mapGetters(['showNum'])
}

2.2.3 Mutations

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

① 只能通过 mutations 变更 Store 数据,不可以直接操作 Store 中的数据。
② 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。

在Vuex中定义

export default new Vuex.Store({
  //数据,相当于data
  state: {
    name:"张三",
    age:12,
    sex: '男',
    count:0
  },
  mutations: {
	addCount(state, num) {
		state.count += num
	},
	reduce(state){
		state.count--
	}
  }
})

在组件中使用:
方法一:使用commit触发Mutations操作

// 触发mutations 
methods: { 
	btn() { 
       // 触发 mutations 的第一种方式 
       this.$store.commit('addCount', 10)     //每次加十
	} 
	btn2() { 
       // 触发 mutations 的第一种方式 
       this.$store.commit('reduce') 
	} 
}

方法二:使用辅助函数进行操作,具体方法同上
从vuex中按需导入mapMutations 函数

// 1. 从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex'

通过刚才导入的 mapMutations 函数,将需要的 mutations 函数,映射为当前组件的 methods 方法

// 2. 将指定的 mutations 函数,映射为当前组件的 methods 函数
methods: {
	// 触发 mutations 的第二种方式 对象写法
	...mapMutations({addCount: 'addCount', reduce:'reduce'}),
	//或是
	// 触发 mutations 的第二种方式 数组写法
	...mapMutations(['addCount', 'reduce']),
	btn() { 
       this.addCount(10)     //每次加十
	} 
	btn2() { 
       this.reduce() 
	} 
}

2.2.4 Actions

Actions 用于处理异步任务。
如果通过异步操作变更数据,必须通过 Actions,而不能使用 Mutation,但是在 Actions 中还是要通过触发Mutation 的方式间接变更数据。

在Vuex中定义:

讲上面的操作改为异步操作

// 定义 Actions
export default new Vuex.Store({ 
	// ...省略其他代码 
	mutations: { 
		//第一个参数是state,第二参数是传的参数
		addCount(state, num) { 
			//state中的数据的改变会触发页面上对应数据的改变
			state.count += num
		},
		reduce(state){
			state.count--
		}
	}, 
	// 异步操作
	actions: { 
		asynReduce(context) { 
			setTimeout(() => { 
				context.commit('reduce') 
			}, 1000) 
		},
		//触发 actions 异步任务时携带参数,第一个参数是上下文对象,第二参数是传的参数
		asynAdd(context, num) { 
			setTimeout(() => { 
				//会找到mutation对应的方法
				context.commit('addCount', num) 
			}, 1000) 
		}  
		
	} 
})

在组件中使用:
方法一:直接使用 dispatch触发Action函数

methods: {
	btn() { 
	   // 触发 actions 的第一种方式
       this.$store.dispatch("asynAdd", 10)
	} 
	btn2() { 
	   // 触发 actions 的第一种方式
       this.$store.dispatch("asynReduce")
	} 
}

方法二:使用辅助函数
从vuex中按需导入mapActions 函数

// 1. 从 vuex 中按需导入 mapActions 函数 
import { mapActions } from 'vuex'

通过刚才导入的 mapActions 函数,将需要的 actions 函数,映射为当前组件的 methods 方法

// 2. 将指定的 actions 函数,映射为当前组件的 methods 函数 
methods: { 
	//对象写法
	...mapActions({asynAdd:'asynAdd', asynReduce:'asynReduce'}),
	//或是
	//数组写法
	...mapActions(['asynAdd', 'asynReduce']),
	
	btn() { 
       this.asynAdd(10)     //每次加十
	} 
	btn2() { 
       this.asynReduce() 
	} 
}

2.2.5 Modules 模块化+命名空间

  1. 目的:让代码更好维护,让多种数据分类更加明确

  2. 场景:当遇见大型项目时,数据量大,store就会显得很臃肿
    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

  3. 基本写法
    写法一:

const countAbout = {
    namespaced: true,
    state: {
    	sum: 0,
    	name: 'zhangsan',
	    sex: 'man',
    },
    mutations: {...},
    actions: {...},
    getters: {
    	bisSum(state){ return state.sum * 10}
}

const personAbout= {
    namespaced: true,
    state: {
		personList: [{
	        id: '0001',
	        name: 'Lisi'
	    }]
	},
    mutations: {...},
    actions: {...},
    getters: { ... }
}

const store = new Vuex.Store({
	modules: {
		countAbout,
		personAbout
	}
})

写法二:

const store = new Vuex.Store({
	modules: {
		countAbout:{
			namespaced: true,
		    state: { ... },
		    mutations: {...},
		    actions: {...},
		    getters: { ... }
		},
		personAbout: {
			namespaced: true,
		    state: { ... },
		    mutations: {...},
		    actions: {...},
		    getters: { ... }
		}
	}
})

默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

  1. 开启命名空间后,组件中读取state数据
//方法一:自己读取
this.$store.state.countAbout.sum
//方法二:借助mapState读取
...mapState('countAbout', ['sum', 'name', 'sex'])
  1. 开启命名空间后,组件中读取getters数据
//方法一:自己读取
this.$store.getters['personAbout/firstPersonName']
//方法二:借助mapGetters读取
...mapGetters('countAbout', ['bisSum'])
  1. 开启命名空间后,组件中调用commit
//方法一:自己commit
this.$store.commit('personAbout/addPerson', person)
//方法二:借助mapMutations读取
...mapMutations('countAbout',{increment: 'add', decrement: 'reduce'})
  1. 开启命名空间后,组件中调用dispatch
//方法一:自己commit
this.$store.dispatch('personAbout/addPersonWang', person)
//方法二:借助mapMutations读取
...mapActions('countAbout',{incrementOdd:'asyncAddOdd', incrementWait:'asyncAddWait'})

3 求和案例

3.1 使用纯vue编写

在这里插入图片描述

App.vue

<template>
  <div class="container">
    <Count/>
  </div>
</template>

<script>
import Countfrom './components/Count'
export default {
  name: 'App',
  components: {Count}
}
</script>
<style></style>

Count.vue

<template>
  <div class="hello">
    <h1>当前求和为:{{sum}}</h1>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button>
  </div>
</template>

<script>
export default {
  name: 'Count',
  data() {
    return {
      n: 1,
      sum: 0
    }
  },
  methods: {
    increment() {
      this.sum += this.n
    },
    decrement() {
      this.sum -= this.n
    },
    incrementOdd() {
      if (this.sum %2) {
        this.sum += this.n
      }
    },
    incrementWait() {
      setTimeout(() => {
        this.sum += this.n
      }, 500);
    }
  }
}
</script>
<style scoped></style>

3.2 使用Vuex编写

3.2.1 原始写法

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'   //引入Vuex

Vue.use(Vuex)    //应用Vuex
 
//创建并暴露store
export default new Vuex.Store({
  //数据,相当于data
  state: {
    sum: 0,
    name: 'zhangsan',
    sex: 'man'
  },
  getters: {},      //里面定义方法,操作state方法
  mutations: {
    add(state, num) {
        state.sum += num
    },
    reduce(state){
        state.sum--
    }
  },    // 操作异步操作mutation
  actions: {
    asyncAddWait(context, num){
        setTimeout(()=>{
            context.commit('add', num)
        },500)
    },
    asyncAddOdd(context, num){
        if(context.state.sum % 2){
            context.commit('add', num)
        }
    }
  },     //用于响应组件中的动作
  modules: {},    
})

Count.vue

<template>
  <div class="hello">
    <h1>当前求和为:{{$store.state.sum}}</h1>
    <h3>当前求和放大10倍:{{$store.getters.bigSum}}</h3>
    <h3>姓名:{{ $store.statename }},性别: {{ $store.statesex }}</h3>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
    <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button>
  </div>
</template>

<script>
export default {
  name: 'Count',
  data() {
    return {
      n: 1
    }
  },
  methods: {
   //使用mutaion
    increment() {this.$store.commit('add', this.n)},
    decrement() { this.$store.commit('reduce')},
	//使用Actions异步
    incrementOdd() {this.$store.dispatch('asyncAddOdd', this.n)},
    incrementWait() {this.$store.dispatch('asyncAddWait', this.n)}
  }
}
</script>
<style scoped></style>

3.2.2 用mapXXX优化后

Count.vue

<template>
  <div class="hello">
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和放大10倍:{{bigSum}}</h3>
    <h3>姓名:{{ name }},性别: {{ sex }}</h3>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
import {mapState,mapGetters,mapMutations, mapActions} from 'vuex'
export default {
  name: 'Count',
  data() {
    return {
      n: 1
    }
  },
  computed: {
    //借助mapSate和mapGetters生成计算属性
    ...mapState(['sum','name','sex']),
    ...mapGetters(['bigSum'])
  },
  methods: {
    ...mapMutations({increment: 'add', decrement: 'reduce'}),
    ...mapActions({incrementOdd:'asyncAddOdd', incrementWait:'asyncAddWait'})
    //使用mutaion
    //increment() {this.$store.commit('add', this.n)},
    //decrement() { this.$store.commit('reduce')},
	//使用Actions异步
    //incrementOdd() {this.$store.dispatch('asyncAddOdd', this.n)},
    //incrementWait() {this.$store.dispatch('asyncAddWait', this.n)}
  }
}
</script>
<style scoped></style>

3.2.2 多组件共享数据

在这里插入图片描述
src/App.vue

<template>
  <div class="container">
    <Count/>
    <Person/>
  </div>
</template>

<script>
import Count from './components/Count'
import Person from './components/Person'
export default {
  name: 'App',
  components: {Count,Person}
}
</script>
<style></style>

src/components/Count.vue

<template>
  <div class="hello">
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和放大10倍:{{bigSum}}</h3>
    <h3>姓名:{{ name }},性别: {{ sex }}</h3>
    <h3 style="color:red">Person组件的总人数是: {{ personList.length }}</h3>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
import {mapState,mapGetters,mapMutations, mapActions} from 'vuex'
export default {
  name: 'Count',
  data() {
    return {
      n: 1
    }
  },
  computed: {
    //借助mapSate和mapGetters生成计算属性
    ...mapState(['sum','name','sex','personList']),
    ...mapGetters(['bigSum'])
  },
  methods: {
    ...mapMutations({increment: 'add', decrement: 'reduce'}),
   ...mapActions({incrementOdd:'asyncAddOdd', incrementWait:'asyncAddWait'})
  }
}
</script>
<style scoped></style>

src/components/Person.vue

<template>
  <div>
    <hr>
    <h1>人员列表</h1>
    <h3 style="color:red">Count组件求和为: {{ sum }}</h3>
    <input type="text" placeholder="请输入" v-model="name">
    <button @click="add">添加</button>
    <br><br>
    <ul>
        <li v-for="p in personList" :key="p.id">{{p.name}}</li>
    </ul>
  </div>
</template>

<script>
import {mapState} from 'vuex'
import {nanoid} from 'nanoid'
export default {
  name: 'Person',
  components: {},
  props: {},
  data() {
    return {
        name: ''
    };
  },
  computed:{
    ...mapState(['personList', 'sum'])
  },
  methods: {
    add() {
        if(this.name === '') return 
        const personObj = {id: nanoid(), name: this.name}
        this.$store.commit('addPerson', personObj)
        this.name = ''
    }
  }
};
</script>
<style scoped></style>

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'   //引入Vuex

Vue.use(Vuex)    //应用Vuex
 
//创建并暴露store
export default new Vuex.Store({
  //数据,相当于data
  state: {
    sum: 0,
    name: 'zhangsan',
    sex: 'man',
    personList: [{
        id: '0001',
        name: 'Lisi'
    }]
  },
  //里面定义方法,操作state方法
  getters: {
    bigSum: state=>{
        return state.sum * 10
    }
  },    
  // 操作异步操作mutation  
  mutations: {
    add(state, num) {
        state.sum += num
    },
    reduce(state){
        state.sum--
    },
    addPerson(state, value) {
        state.personList.unshift(value)
    }
  },   
  //用于响应组件中的动作 
  actions: {
    asyncAddWait(context, num){
        setTimeout(()=>{
            context.commit('add', num)
        },500)
    },
    asyncAddOdd(context, num){
        if(context.state.sum % 2){
            context.commit('add', num)
        }
    }
  },     
})

3.2.3 模块化优化后

在这里插入图片描述

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'   //引入Vuex
import countOptions from './count'
import personOptions from './person'
import count from './count'
Vue.use(Vuex)    //应用Vuex
 
//创建并暴露store
export default new Vuex.Store({
  modules: {
    countAbout: countOptions,
    personAbout: personOptions
  },    
})

src/store/count.js

export default {
    namespaced: true,
    state: {
        sum: 0,
        name: 'zhangsan',
        sex: 'man',
    },
    getters: {
        bigSum(state){return state.sum * 10}
    },
    mutations: {
        add(state, num) {
            state.sum += num
        },
        reduce(state){
            state.sum--
        },
    },
    actions: {
        asyncAddWait(context, num){
            setTimeout(()=>{
                context.commit('add', num)
            },500)
        },
        asyncAddOdd(context, num){
            if(context.state.sum % 2){
                context.commit('add', num)
            }
        }
    }
}

src/store/person.js

import axios from "axios"
import { nanoid } from 'nanoid'

export default {
    namespaced: true,
    state: {
        personList: [{
            id: '0001',
            name: 'Lisi'
        }]
    },
    getters: {
        firstPersonName(state) {return state.personList[0].name}
    },
    mutations: {
        addPerson(state, value) {
            state.personList.unshift(value)
        }
    },
    actions: {
        addPersonWang(context, value) {
            if(value.name.indexOf('王') === 0){
                context.commit('addPerson', value)
            }else {
                alert('添加的人必须为王')
            }
        },
        addPersonServer(context) {
            axios.get('http://api.uixsj.cn/hitokoto/get?type=social').then(
                response => {
                    context.commit('addPerson', {id: nanoid(), name:response.data})
                },
                error => {
                    alert(error.message)
                }
            )
        }
    }
}

Count和Person的呈现了两种不同的写法,一个是用mapXXX的写法,一个是直接使用this.$store的写法
src/components/Count.vue

<template>
  <div class="hello">
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和放大10倍:{{bigSum}}</h3>
    <h3>姓名:{{ name }},性别: {{ sex }}</h3>
    <h3 style="color:red">Person组件的总人数是: {{ personList.length }}</h3>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
import {mapState,mapGetters,mapMutations, mapActions} from 'vuex'
export default {
  name: 'Count',
  data() {
    return {
      n: 1
    }
  },
  computed: {
    //借助mapSate和mapGetters生成计算属性
    ...mapState('countAbout',['sum','name','sex']),
    ...mapState('personAbout', ['personList']),
    ...mapGetters('countAbout',['bigSum'])
  },
  methods: {
    ...mapMutations('countAbout',{increment: 'add', decrement: 'reduce'}),
    ...mapActions('countAbout',{incrementOdd:'asyncAddOdd', incrementWait:'asyncAddWait'})
  }
}
</script>
<style scoped></style>

src/components/Person.vue

<template>
  <div>
    <hr>
    <h1>人员列表</h1>
    <h3 style="color:red">Count组件求和为: {{ sum }}</h3>
    <h3>列表中第一个人的名字是: {{ firstPersonName }}</h3>
    <input type="text" placeholder="请输入" v-model="name">
    <button @click="add">添加</button>
    <button @click="addWang">添加一个姓王的人</button>
    <button @click="addRandom">随机添加一个人</button>
    <br><br>
    <ul>
        <li v-for="p in personList" :key="p.id">{{p.name}}</li>
    </ul>
  </div>
</template>

<script>
import {mapState, mapGetters,mapMutations,mapActions} from 'vuex'
import {nanoid} from 'nanoid'
export default {
  name: 'Person',
  components: {},
  props: {},
  data() {
    return {
        name: ''
    };
  },
  computed:{
    //直接读取的方法
    personList() { return this.$store.state.personAbout.personList },
    sum() { return this.$store.state.countAbout.sum },
    firstPersonName() { return this.$store.getters['personAbout/firstPersonName'] }
  },
  methods: {
    add() {
        if(this.name === '') return 
        const personObj = {id: nanoid(), name: this.name}
        this.$store.commit('personAbout/addPerson', personObj)
        this.name = ''
    },
    addWang() {
        if(this.name === '') return 
        const personObj = {id: nanoid(), name: this.name}
        this.$store.dispatch('personAbout/addPersonWang', personObj)
        this.name = ''
    },
    addRandom() {
        this.$store.dispatch('personAbout/addPersonServer')
    }
  }
};
</script>
<style scoped>
</style>

4 求和案例2

4.1 props传递值

helloword子组件使用Home组件声明的变量,可采用之前学习的组件传递值的方法

Home组件

<template>
  <div class="home">
    <h2>这是在单页模板中应用</h2>
    <h3>{{count}}</h3>
    <button @click="count--">-</button>
    <button @click="count++">+</button>
    <!-- 传递count给子组件helloword--->
    <HelloWorld :count="count" msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
  name: 'Home',
  components: {
    HelloWorld
  },
  data() {
    return {
      count: 0
    }
  }
}
</script>

helloword子组件

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h3>在子组件hellword中应用Home中的Data</h3>
    <h3>{{count}}</h3>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    count: Number
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
……
</style>

效果在这里插入图片描述
若About组件想要使用Home组件的count,通过组件传递的方式也可实现,就是有点麻烦,需要传递给中介App组件,App组件再传递给About组件。

4.2 Vuex的state传递

因此,在这里可采用Vuex,其配置文件在/store/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    //任何地方都可使用这个状态管理
    num: 0
  },
  mutations: { },
  actions: {},
  modules: {}
})

Home.vue

<template>
  <div class="home">
    <h2>使用全局的状态管理</h2>
    <h3>{{$store.state.num}}</h3>
    <button @click="$store.state.num--">-</button>
    <button @click="$store.state.num++">+</button>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',
  components: {
    HelloWorld
  },
}
</script>

About.vue

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h3>{{$store.state.num}}</h3>
  </div>
</template>

效果
在这里插入图片描述
在这里插入图片描述

4.3 Matuations来修改状态

Vuex最好采用Matuations来修改状态,而不是通过组件的形式
index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    //任何地方都可使用这个状态管理
    num: 0,
    mnum: 0
  },
  mutations: {
    //自动把state的参数传过来
    sub(state) {
      state.mnum--;
    },
    add(state) {
      state.mnum++;
    }
  },
  actions: { },
  modules: {}
})

Home.vue

<template>
  <div class="home">
    <h2>这是在单页模板中应用</h2>
    <h3>{{count}}</h3>
    <button @click="count--">-</button>
    <button @click="count++">+</button>
    <HelloWorld :count="count" msg="Welcome to Your Vue.js App"/>
    <hr>
    <h2>使用全局的状态管理</h2>
    <h3>{{$store.state.num}}</h3>
    <button @click="$store.state.num--">-</button>
    <button @click="$store.state.num++">+</button>
    <hr>
    <h2>使用Mutations来修改状态</h2>
    <h3>MNum:{{$store.state.mnum}}</h3>
    <button @click="sub1()">-</button>
    <button @click="add1()">+</button>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',
  components: {
    HelloWorld
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    add1() {
      this.$store.commit('add')
    },
    sub1() {
      this.$store.commit('sub')
    },
  }
}
</script>

About.vue

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h3>Num:{{$store.state.num}}</h3>
    <h3>MNum:{{$store.state.mnum}}</h3>
  </div>
</template>

效果
在这里插入图片描述
在这里插入图片描述

4.4 Mutations带参数传递修改状态

index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    //任何地方都可使用这个状态管理
    num: 0,
    mnum: 0
  },
  mutations: {
    //自动把state的参数传过来
    sub(state) {
      state.mnum--;
    },
    add(state) {
      state.mnum++;
    },
    //接收一个参数
    sub2(state,count) {
      console.log(count);
      state.mnum-=count;
    },
    add2(state,count) {
      console.log(count);
      state.mnum+=count;
    },
    //接收多个参数
    sub3(state,payload) {
      console.log(payload);
      state.mnum-=(payload.count+payload.num);
    },
    add3(state,payload) {
      console.log(payload);
      state.mnum+=(payload.count+payload.num);
    }

  },
  actions: {},
  modules: {}
})

Home.vue

<template>
  <div class="home">
    <hr>
    <h2>使用Mutations来修改状态</h2>
    <h3>MNum:{{$store.state.mnum}}</h3>
    <button @click="sub1()">-</button>
    <button @click="add1()">+</button>
    <hr>
    <h2>使用Mutations来修改状态带一个参数</h2>
    <h3>MNum:{{$store.state.mnum}}</h3>
    <button @click="sub2()">-</button>
    <button @click="add2()">+</button>
    <hr>
    <h2>使用Mutations来修改状态带多个参数</h2>
    <h3>MNum:{{$store.state.mnum}}</h3>
    <button @click="sub3()">-</button>
    <button @click="add3()">+</button>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'Home',
  components: {
    HelloWorld
  },
  data() {
    return {
      count: 0
    }
  },
  methods: {
    add1() {
      this.$store.commit('add')
    },
    sub1() {
      this.$store.commit('sub')
    },
    add2() {
      let count = 2;
      this.$store.commit('add2',count)
    },
    sub2() {
      let count = 2;
      this.$store.commit('sub2',count)
    },
    add3() {
      let payload = {count:2, num:1}
      this.$store.commit('add3',payload)
    },
    sub3() {
      let payload = {count:2, num:1}
      this.$store.commit('sub3',payload)
      //等价于
      //this.$store.commit({type:'sub3', payload})
    }
  }
}
</script>

效果
在这里插入图片描述

5 多组件共享数据案例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/655835.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Property ‘code‘ does not exist on type ‘AxiosResponse<any, any>‘ 的解决办法

原文链接 : Property ‘xxx’ does not exist on type ‘AxiosResponse<any, any>’ 的解决办法 vue3 ts 中 调用接口时&#xff1a; const loginOut () > {loginOutApi().then(res > {const { code } resif(code 0){ }})}报了如下错误&#xff1a; Property…

Python基础(3)——PyCharm介绍

Python基础&#xff08;3&#xff09;——PyCharm介绍 文章目录 Python基础&#xff08;3&#xff09;——PyCharm介绍课程目标一. PyCharm的作用二. 下载和安装2.1 下载2.2 安装 三. PyCharm基本使用3.1 新建项目3.2 新建文件并书写代码3.3 运行文件 四. PyCharm的基本设置4.1…

基于Hexo和Butterfly创建个人技术博客,(10) 使用Butterfly的Tags Plugin插件增强博客文章内容和视觉表现力

Butterfly官方网站&#xff0c;请 点击进入 说明&#xff1a; 前面已经提过Hexo自创了Tag Plugin内容标签&#xff0c;Butterflay主题在此基础上又扩展了一些。本文就详细讲解下这些标签带来哪些额外的功能和UI方面的强化&#xff1b; 本章目标&#xff1a; 掌握butterfly扩展…

LightningChart .NET 10.5.1 Crack LightningChart 2023

LightningChart .NET v.10.5.1 已经发布&#xff01; DataCursor 和 3D TransparencyRenderMode 现在可用。 为所有 3D、Polar 和 Smith 系列启用 DataCursor 在早期阶段&#xff0c;LightningChart 提供了不同的工具&#xff0c;需要用户编写额外的代码才能启用数据跟踪功能。…

phpstudy免费下载

phpstudy免费下载 phpstudy是一个可以在本地建站的php环境软件链接: https://pan.baidu.com/s/1vfi-gy3juYBUjGz_Cq2gHg 提取码: 1234链接: http://120.26.240.154:8888/down/5Sx9yB0s0HS3.zip phpstudy是一个可以在本地建站的php环境软件 百度网盘分享 链接: https://pan.ba…

Session和Cookie,你真的弄清了吗?

Session和Cookie Session和Cookie Session和Cookiecookiecookie的生命周期cookie作用域 Sessionsession的生命周期session作用域 cookie和session安全性 为什么需要cookie和session&#xff1f;在web系统发展变迁时&#xff0c;web发展时随着需求的不断增多&#xff0c;交互的存…

Ceph:关于Ceph 集群中池管理的一些笔记

写在前面 准备考试&#xff0c;整理 Ceph 相关笔记博文内容涉及, Ceph 中的 两种 pool 介绍&#xff0c;创建操作管理池理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停…

java公益网站系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目wap

一、源码特点 java 公益网站系统是一套完善的java web wap信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

Ceph:关于Ceph 集群管理的一些笔记

写在前面 准备考试&#xff0c;整理ceph 相关笔记博文内容涉及&#xff0c;Ceph 管理工具 cephadm&#xff0c;ceph 编排器&#xff0c;Ceph CLI 和 Dashboard GUI 介绍理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守…

Android插件化框架-Shadow原理解析

作者&#xff1a;dennyz 1、前言 所谓插件化&#xff0c;是实现动态化的一种具体的技术手段。 对于移动端的App而言&#xff0c;无论是Android还是iOS&#xff0c;都存在一个共同的问题&#xff0c;那就是更新的周期较长。 当我们希望快速为App更新功能时&#xff0c;必须经…

Docker Desktop启动失败解决方案(亲侧出坑总结)

现在有些东西网上资料开始变少了。需要自己去总结。有些技术呢又因为分享变得门槛低。今天这个是关于windows下的docker desktop无法启动的问题集锦。卷吧。 背景&#xff1a;应业务需要所以需要在个人电脑上安装docker环境。desktop docker是官方标准的windows下安装工具。 …

6.7面向对象的多态

7. 面向对象特征三&#xff1a;多态性 概念 多态是面向对象程序设计&#xff08;OOP&#xff09;的一个重要特征&#xff0c;指同一个实体同时具有多种形式&#xff0c;即同一个对象&#xff0c;在不同时刻&#xff0c;代表的对象不一样&#xff0c;指的是对象的多种形态。 变…

副业变现:Midjourney绘画赚钱的6种方式

今年被称为AI元年&#xff0c;其中最火的两款AI工具非ChatGpt和Midjourney莫属。究其原因&#xff0c;无非两点&#xff1a;第一&#xff0c;它提高了生产力&#xff0c;之前需要两年完成的工作&#xff0c;使用ChatGpt两天就完成。 第二&#xff0c;它带来了副业收入&#xff…

短视频seo源代码部署步骤

一、 部署短视频SEO矩阵系统源代码&#xff0c;您需要遵循以下步骤&#xff1a; 准备服务器环境 首先&#xff0c;您需要准备一个服务器环境来托管源代码。您可以选择云服务器&#xff08;例如AWS&#xff0c;阿里云等&#xff09;或自己的私人服务器。 安装所需软件 在服务器…

Android系统Binder详解

Android系统启动篇 1&#xff0c;《android系统启动流程简介》 2&#xff0c;《android init进程启动流程》 3&#xff0c;《android zygote进程启动流程》 4&#xff0c;《Android SystemServer进程启动流程》 5&#xff0c;《android launcher启动流程》 6&#xff0c;…

visual studio编译c++问题处理

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C2760 语法错误: 意外的令牌“标识符”&#xff0c;预期的令牌为“;” 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C7510 “string_view”: 类型 从属名称的使用必须…

RocketMQ_介绍以及基础入门

目录 一、什么是MQ 1、应用解耦 2、流量削峰 3、数据分发 二、MQ的优缺点 三、各种MQ产品的对比 四、RocketMQ快速入门(单机版本) 一、什么是MQ 在学习RocketMQ之前&#xff0c;我们先来了解什么是MQ&#xff0c;以及为什么要用MQ。MQ的英文全称是&#xff08;Massage Q…

2023首届盘古石杯晋级赛复盘

晋级赛通排61&#xff0c;学生组39&#xff0c;折在大小写格式上的题太多了qaq 容器密码&#xff1a;usy1UN2Mmgram&^d?0E5r9myrk!cmJGr Android程序分析 1.涉案应用刷刷樂的签名序列号是(答案格式&#xff1a;123ca12a)(★☆☆☆☆) 11fcf899 雷电APP跑的时候前面加…

LeetCode 2481. 分割圆的最少切割次数

【LetMeFly】2481.分割圆的最少切割次数 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-cuts-to-divide-a-circle/ 圆内一个 有效切割 &#xff0c;符合以下二者之一&#xff1a; 该切割是两个端点在圆上的线段&#xff0c;且该线段经过圆心。该切割是一端…

【Flutter】Flutter 如何使用 flutter_swiper

文章目录 一、前言二、flutter_swiper 的概念三、Flutter 中的 flutter_swiper1. 使用的库2. 方法介绍 四、代码示例1. 简单示例2. 完整示例 五、总结 一、前言 在移动应用开发中&#xff0c;轮播图是一种常见的 UI 元素&#xff0c;它可以用来展示一系列的图片或者内容。在 F…