目录
一、vuex
1.定义
专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应 用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
原理图:
State | VuexVue.js 的中心化状态管理方案
https://vuex.vuejs.org/zh/guide/state.html
vuex多应用于多个组件应用与同一个状态,多个组件变更同一状态。
- Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
什么是“状态管理模式”?
这个状态自管理应用包含以下几个部分:
- 状态,驱动应用的数据源;
- 视图,以声明方式将状态映射到视图;
- 操作,响应在视图上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的简单示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
2.安装
npm i vuex@3 注释:@3是版本号,vue2用vuex@3版本,vue3用4版本
二、store创建
1.定义
概念:每一个Vuex应用的核心就是Store(仓库),我们可以说Store是一个容器,它包含着你的应用中大部分的状态 (state)。但Store里面的状态与单纯的全局变量是不一样的,无法直接改变Store中的状态。想要改变状态需通过mutation去修改。
Vuex 和单纯的全局对象有以下两点不同:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
2.结构
创建文件夹store与src根目录下,建立index.js。需包含actions,mutations,state结构如下:
import Vue from 'vue' // 引入vue
import Vuex from 'vuex' // 引入vuex
Vue.use(Vuex) // 应用vue插件
// actions响应组件中的动作
const actions = { }
// mutations操作数据state
const mutations = { }
// 准备state存储数据
const state = {
//状态对象
}
//想要对状态有要进一步的加工时可以用到
//getters 从 store 中的 state 中派生出一些状态
const getters={
randmajor(state){
return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
}
}
// 创建store并导出
const store = new Vuex.Store({
actions,
mutations,
state,
getters
})
//默认导出store
export default store
3.引入store
在main.js中引入store,全局组件都可以使用vuex。
import store from './store'
new Vue({
render: h => h(App),
store,
}).$mount('#app')
三、状态的核心概念
1. state
state是状态数据,可以通过this.$store.state来直接获取状态,也可以利用vuex提供的mapState辅助函数将state映射到计算属性(computed)中去。
示例:
1. index.js
const state = {
//状态对象
name:'2209',
major:'web前端',
}
2. 两个组件中的写法
1)插值引用:{{$store.state.name}}
<h2>班级:{{$store.state.name}},专业:{{$store.state.major}}</h2>
2)在计算属性中写法
<h2>班级:{{name}},专业:{{major}}</h2>
computed:{
name(){
return this.$store.state.name;
},
major(){
return this.$store.state.major;
}
}
3)数据映射写法
<h2>班级:{{myname}},专业:{{mymajor}}</h2>
import {mapState} from 'vuex'
computed:{
// 当计算属性的名称与vuex一致的时候 用数组形式
// ...mapState(["name","major"]),
// 当计算属性的名称与vuex不一致的时候 用对象形式
...mapState({myname:"name",mymajor:"major"}),
}
2. actions
Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。
// actions响应组件中的动作
//context 上下文,value组件传递过来的值
//可以包含定时器,ajax代码,有业务逻辑使用action,无业务逻辑直接使用mutations
//index.js中
const actions = {
editwait(context,value){
setTimeout(()=>{
context.commit('editmajor',value);
},3000)
}
}
在组件中使用: $store.dispatch('对应的 action 回调名') 触发
<button @click="editwait('java')">等3s更改专业</button>
methods:{
editwait(str){
this.$store.dispatch('editwait',str);
}
}
用数据映射触发
<button @click="editwait('java')">等3s更改专业</button>
import {mapActions } from 'vuex'
methods:{
...mapActions(['editwait']),
}
3. mutations
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
index.js:
// mutations操作数据state
const mutations = {
editname(state,value){
state.name=value;
},
editmajor(state,value){
state.major=value;
},
}
组件中触发:
<button @click="editname('2209班')">修改班级</button>
<button @click="editmajor('vue')">修改专业</button>
methods:{
editname(){
this.$store.commit('editname','2209班')
},
editmajor(){
this.$store.commit('editmajor','vue')
},
}
此时的mutations 无业务逻辑,就是更改状态。
数据映射方法:
<button @click="editname('2209班')">修改班级</button>
<button @click="editmajor('vue')">修改专业</button>
import {mapActions } from 'vuex'
methods:{
...mapActions(['editwait']),
}
4. getters
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数,也就是对状态在加工:
index.js:
//getter 从 store 中的 state 中派生出一些状态
const getters={
randmajor(state){
return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
}
}
组件中调用数据:
<h3>专业+随机数:{{randmajor}}</h3>
computed:{
randmajor(){
return this.$store.getters.randmajor;
}
},
数据映射方法:
<h3>专业+随机数:{{randmajor}}</h3>
import {mapGetters } from 'vuex'
computed:{
...mapGetters(['randmajor']),
},
5.数据映射
三点运算符的形式书写
mapMutations和mapActions:
借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
mapState和mapGetters:
mapState(mapGetters)生成计算属性,从state中读取状态(对象形式)
6. 案列示例
index.js部分
//需包含actions,mutations,state
// 引入vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 应用vue插件
Vue.use(Vuex)
//1
// 准备state存储数据
const state = {
//状态对象
name:'2209',
major:'web前端',
}
// actions响应组件中的动作 可以包含任意异步操作
const actions = {
editwait(context,value){
setTimeout(()=>{
context.commit('editmajor',value);
},3000)
}
}
// mutations操作数据state
const mutations = {
editname(state,value){
state.name=value;
},
editmajor(state,value){
state.major=value;
},
}
//getter 从 store 中的 state 中派生出一些状态
const getters={
randmajor(state){
return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
}
}
//创建store并导出
const store = new Vuex.Store({
actions,
mutations,
state,
getters
})
//默认导出store
export default store
组件1
<template>
<div>
<!-- <h2>班级:{{$store.state.name}},专业:{{$store.state.major}}</h2> -->
<!-- <h2>班级:{{name}},专业:{{major}}</h2> -->
<h2>班级:{{myname}},专业:{{mymajor}}</h2>
<h3>专业+随机数:{{randmajor}}</h3>
<p>姓名:张三,年龄:18</p>
<button @click="editname('2209班')">修改班级</button>
<button @click="editmajor('vue')">修改专业</button>
<button @click="editwait('java')">等3s更改专业</button>
</div>
</template>
<script>
import {mapActions, mapGetters, mapMutations, mapState, } from 'vuex'
export default {
name:'ZhangSan',
computed:{
// name(){
// return this.$store.state.name;
// },
// major(){
// return this.$store.state.major;
// }
// 当计算属性的名称与vuex一致的时候 用数组形式
// ...mapState(["name","major"]),
// 当计算属性的名称与vuex不一致的时候 用对象形式
...mapState({myname:"name",mymajor:"major"}),
// randmajor(){
// return this.$store.getters.randmajor;
// }
...mapGetters(['randmajor']),
},
methods:{
editname(){
this.$store.commit('editname','2209班')
},
editmajor(){
this.$store.commit('editmajor','vue')
},
...mapMutations(['editname','editmajor']),
// editwait(str){
// this.$store.dispatch('editwait',str);
// }
...mapActions(['editwait']),
}
}
</script>
<style scoped>
</style>
组件2
<template>
<div>
<!-- <h2>班级:{{$store.state.name}},专业:{{$store.state.major}}</h2> -->
<!-- <h2>班级:{{name}},专业:{{major}}</h2> -->
<h2>班级:{{myname}},专业:{{mymajor}}</h2>
<h3>专业+随机数:{{randmajor}}</h3>
<p>姓名:李四,年龄:20</p>
</div>
</template>
<script>
import {mapState,} from 'vuex'
export default {
name:'LiSi',
computed:{
// name(){
// return this.$store.state.name;
// },
// major(){
// return this.$store.state.major;
// }
// 当计算属性的名称与vuex一致的时候 用数组形式
// ...mapState(["name","major"]),
// 当计算属性的名称与vuex不一致的时候 用对象形式
...mapState({myname:"name",mymajor:"major"}),
randmajor(){
return this.$store.getters.randmajor;
}
}
}
</script>
<style scoped>
</style>
整体效果:
共享状态,通过store把数据共享给两个组件,所以组件里的数据状态会随store里的数据变化而变化
四、模块化编码(modules)
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割在模块中使用:namespaced: true, 命名空间,添加之后,当前模块下的标识符可以和其它模块相同,用于解决不同模块的命名冲突问题
就上面一个示例来进行模块化编码:
index,js部分
//需包含actions,mutations,state
// 引入vue
import Vue from 'vue'
// 引入vuex
import Vuex from 'vuex'
// 应用vue插件
Vue.use(Vuex)
const Persons={
namespaced:true,
state:{
//状态对象
name:'2209',
major:'web前端',
},
actions:{
editwait(context,value){
setTimeout(()=>{
context.commit('editmajor',value);
},3000);
}
},
mutations:{
editname(state,value){
state.name=value;
},
editmajor(state,value){
state.major=value;
},
},
getters:{
randmajor(state){
return state.major+Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9) + Math.ceil(Math.random()*9);
}
}
}
//创建store并导出
const store = new Vuex.Store({
modules:{
Persons
}
})
//默认导出store
export default store
组件1
<template>
<div>
<!-- <h2>班级:{{$store.state.name}},专业:{{$store.state.major}}</h2> -->
<!-- <h2>班级:{{name}},专业:{{major}}</h2> -->
<h2>班级:{{myname}},专业:{{mymajor}}</h2>
<h3>专业+随机数:{{randmajor}}</h3>
<p>姓名:张三,年龄:18</p>
<button @click="editname('2209班')">修改班级</button>
<button @click="editmajor('vue')">修改专业</button>
<button @click="editwait('java')">等3s更改专业</button>
</div>
</template>
<script>
import {mapActions, mapGetters, mapMutations, mapState, } from 'vuex'
export default {
name:'ZhangSan',
computed:{
...mapState('Persons',{myname:"name",mymajor:"major"}),
...mapGetters('Persons',['randmajor']),
},
methods:{
...mapMutations('Persons',['editname','editmajor']),
...mapActions('Persons',['editwait']),
}
}
</script>
<style scoped>
</style>
组件2
<template>
<div>
<!-- <h2>班级:{{$store.state.name}},专业:{{$store.state.major}}</h2> -->
<!-- <h2>班级:{{name}},专业:{{major}}</h2> -->
<h2>班级:{{myname}},专业:{{mymajor}}</h2>
<h3>专业+随机数:{{randmajor}}</h3>
<p>姓名:李四,年龄:20</p>
</div>
</template>
<script>
import {mapState,mapGetters} from 'vuex'
export default {
name:'LiSi',
computed:{
...mapState('Persons',{myname:"name",mymajor:"major"}),
...mapGetters('Persons',['randmajor']),
}
}
</script>
<style scoped>
</style>
代码运行效果和上例一样