VUE vuex深入浅出


image.png

①state:定义初始数据。

②mutations:更改Vuex的store中的状态的唯一方法是提交mutation

③getters:可以对state 进行计算操作,它就是 store 的计算属性虽然在组件内也可以做计算属性,但是 getters 可以在多给件之间复用如果一个状态只在一个组件内使用,是可以不用 getters。

④actions:异步操作初始数据,其实就是调用mutations里面的方法。

⑤module:面对复杂的应用程序,当管理的状态比较多时;我们需要将vuex的store对象分割成模块(modules)。

store文件夹index.js文件

复制代码
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        lists: [
            // { id: 4, name: 'DS', ctime: "2020/01/01" },
            // { id: 3, name: '奥迪', ctime: "2020/01/01" },
            // { id: 2, name: '宝马', ctime: "2020/01/01" },
            // { id: 1, name: '奔驰', ctime: "2020/01/01" },
        ],
        brand: {}
    },

    mutations: {
        init(state, list) {
            state.lists = list
        },
        del(state, id) { //state 上下文的state  id外界传过来的值
            const index = state.lists.findIndex(item => item.id == id)
            state.lists.splice(index, 1)
        },
        add(state, brand) {
            state.lists.unshift(brand)
        }
    },
    getters: {
        getCount(state) {
            return state.lists.length
        }
    },
    actions: {
        getList(context) {
            console.log(context)
            const list = [
                { id: 4, name: 'DS', ctime: "2020/01/01" },
                { id: 3, name: '奥迪', ctime: "2020/01/01" },
                { id: 2, name: '宝马', ctime: "2020/01/01" },
                { id: 1, name: '奔驰', ctime: "2020/01/01" },
            ]
            setTimeout(() => {
                context.commit('init', list)
            }, 2000)
        }
    },
    modules: {}
})

add.vue 文件

复制代码
<template>
  <div class="container">
    <el-form :model="$store.state.brand" label-width="150px">
      <el-form-item label="品牌名称:">
        <el-input v-model="$store.state.brand.name" placeholder="请输入品牌名称"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">立即创建</el-button>

      </el-form-item>
    </el-form>
  </div>
</template>

<script>
export default {
  name: "add",

  methods: {
    onSubmit() {
      console.log(this.$store.state.brand.name)
      const obj = {
        id: this.$store.state.lists[0].id + 1,
        name: this.$store.state.brand.name,
        ctime: new Date().toLocaleDateString()
      }
      this.$store.commit('add', obj)
    }
  },
}
</script>

<style>
</style>

父组件

复制代码
<template>
  <div class="container">
    <Add />
    <hr>
    <h3>品牌总数:{{getCount}}</h3>
    <template>
      <el-table :data="lists" style="width: 100%" border>
        <el-table-column prop="id" label="品牌id" align="center" header-align="center">
        </el-table-column>
        <el-table-column prop="name" label="品牌名称" align="center" header-align="center">
        </el-table-column>
        <el-table-column prop="ctime" label="添加时间" align="center" header-align="center">
        </el-table-column>
        <el-table-column label="操作" align="center" header-align="center">
          <template slot-scope="scope">
            <el-button type="success" @click="handleEdit(scope.row.id)">编辑</el-button>
            <el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </template>
  </div>
</template>

<script>
import Add from "./Add"
// mapState():将vuex中的状态数据映射到组件内部
import { mapState } from "vuex" //放到computed解构
import { mapGetters } from "vuex" //放到computed解构

import { mapMutations } from 'vuex' //放到methods 解构
import { mapActions } from 'vuex' //放到methods 解构
export default {
  name: "helle",
  components: {
    Add
  },
  created() {
    // this.$store.dispatch('getList')
    this.getList()
    console.log(mapState(["lists", "brand"]))
  },
  computed: {
    ...mapState(["lists", "brand"]),
    ...mapGetters(['getCount'])
  },
  methods: {
    ...mapMutations(['del']),
    ...mapActions(['getList']),
    handleEdit(id) {
      console.log(id)
    },
    handleDelete(id) {
      console.log(id)
      //通过this.$store.commit方法触发mutations种定义的del方法 第二个为传递的参数
      // this.$store.commit('del', id)
      this.del(id)
    }
  },

}
</script>

<style>
</style>
Vuex是什么?

Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。

使用 Vuex 统一管理状态的好处

① 能够在 vuex 中集中管理共享的数据,易于开发和后期维护

② 能够高效地实现组件之间的数据共享,提高开发效率

③ 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步

一般情况下,只有组件之间共享的数据,才有必要存储到 vuex 中;对于组件中的私有数据,依旧存储在组件自身的 data 中即可

Vuex 的基本使用
复制代码
npm install vuex --save    安装 vuex 依赖包
import Vuex from 'vuex'
Vue.use(Vuex)               导入 vuex 包
const store = new Vuex.Store({
 // state 中存放的就是全局共享的数据
   state: { count: 0 }
})
new Vue({
 el: '#app',
 render: h => h(app),
 router,
 // 将创建的共享数据对象,挂载到 Vue 实例中
 // 所有的组件,就可以直接从 store 中获取全局的数据了
 store
})
Vuex 中的主要核心
State

State 提供唯一的公共数据源,所有共享的数据都要统一放到 Store 的 State 中进行存储。

复制代码
// 创建store数据源,提供唯一公共数据
 const store = new Vuex.Store({
       state: { count: 0 }
 })

组件访问 State 中数据的第一种方式:
this.$store.state.全局数据名称

组件访问 State 中数据的第二种方式:

复制代码
// 1\. 从 vuex 中按需导入 mapState 函数
import { mapState } from 'vuex'
通过刚才导入的 mapState 函数,将当前组件需要的全局数据,映射为当前组件的 computed 计算属性:
// 2\. 将全局数据,映射为当前组件的计算属性
computed: {
   ...mapState(['count'])
}
Mutation

Mutation 用于变更 Store中 的数据。

只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据。

通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。

复制代码
// 定义 Mutation
 const store = new Vuex.Store({
       state: {
           count: 0
       },
       mutations: {
           add(state) {
           // 变更状态
               state.count++
           }
       }
 })

 // 触发mutation
 methods: {
 handle1() {
 // 触发 mutations 的第一种方式
 this.$store.commit('add')
 }
 }

可以在触发 mutations 时传递参数:

复制代码
 // 定义Mutation
 const store = new Vuex.Store({
       state: {
           count: 0
       },
       mutations: {
           addN(state, step) {
           // 变更状态
           state.count += step
           }
       }
 })

 // 触发mutation
 methods: {
     handle2() {
     // 在调用 commit 函数,
     // 触发 mutations 时携带参数
           this.$store.commit('addN', 3)
         }
   }

this.$store.commit() 是触发 mutations 的第一种方式

触发 mutations 的第二种方式:

复制代码
// 1\. 从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex'
通过刚才导入的 mapMutations 函数,将需要的 mutations 函数,映射为当前组件的 methods 方法:
// 2\. 将指定的 mutations 函数,映射为当前组件的 methods 函数
methods: {
 ...mapMutations(['add', 'addN'])
}
Action

Action 用于处理异步任务。

如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但是在 Action 中还是要通过触发

Mutation 的方式间接变更数据

复制代码
 // 定义 Action
 const store = new Vuex.Store({
 // ...省略其他代码
     mutations: {
         add(state) {
         state.count++
     }
 },
 actions: {
     addAsync(context) {
         setTimeout(() => {
             context.commit('add')
     }, 1000)
   } 
 }
 }) 
 // 触发 Action
 methods: {
     handle() {
     // 触发 actions 的第一种方式
     this.$store.dispatch('addAsync')
     }
 }

触发 actions 异步任务时携带参数:

复制代码
// 定义 Action
 const store = new Vuex.Store({
 // ...省略其他代码
     mutations: {
     addN(state, step) {
     state.count += step
     }
 },
     actions: {
         addNAsync(context, step) {
             setTimeout(() => {
                 context.commit('addN', step)
             }, 1000)
         } 
     }
 })
// 触发 Action
 methods: {
     handle() {
     // 在调用 dispatch 函数,
    // 触发 actions 时携带参数
         this.$store.dispatch('addNAsync', 5)
      }
   }

this.$store.dispatch() 是触发 actions 的第一种方式

触发 actions 的第二种方式:

复制代码
// 1\. 从 vuex 中按需导入 mapActions 函数
import { mapActions } from 'vuex'
通过刚才导入的 mapActions 函数,将需要的 actions 函数,映射为当前组件的 methods 方法:
// 2\. 将指定的 actions 函数,映射为当前组件的 methods 函数
methods: {
 ...mapActions(['addASync', 'addNASync'])
}
Getter

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

Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue 的计算属性。

Store 中数据发生变化,Getter 的数据也会跟着变化。

复制代码
 // 定义 Getter
    const store = new Vuex.Store({
      state: {
        count: 0
      },
      getters: {
        showNum: state => {
          return '当前最新的数量是【' + state.count + '】'
        }
      }
    })

使用 getters 的第一种方式:this.$store.getters.名称

使用 getters 的第二种方式:

复制代码
import { mapGetters } from 'vuex'
computed: {
     ...mapGetters(['showNum'])
}

2.2 Mutations

mutations是操作state数据的方法的集合,比如对该数据的修改、增加、删除等等。

2.2.1 Mutations使用方法

mutations方法都有默认的形参:

([state] [,payload])

  • state是当前VueX对象中的state
  • payload是该方法在被调用时传递参数使用的
例如,我们编写一个方法,当被执行时,能把下例中的name值修改为"jack",我们只需要这样做:
复制代码
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.store({
    state:{
        name:'helloVueX'
    },
    mutations:{
        //es6语法,等同edit:funcion(){...}
        edit(state){
            state.name = 'jack'
        }
    }

而在组件中,我们需要这样去调用这个mutation------例如在App.vue的某个method中:

复制代码
this.$store.commit('edit')

2.2.2 Mutation传值

在实际生产过程中,会遇到需要在提交某个mutation时需要携带一些参数给方法使用。

单个值提交时:

复制代码
this.$store.commit('edit',15)

当需要多参提交时,推荐把他们放在一个对象中来提交:

复制代码
this.$store.commit('edit',{age:15,sex:'男'})

接收挂载的参数:

复制代码
          edit(state,payload){
            state.name = 'jack'
            console.log(payload) // 15或{age:15,sex:'男'}
        }

另一种提交方式

复制代码
this.$store.commit({
    type:'edit',
    payload:{
        age:15,
        sex:'男'
    }
})

2.2.3 增删state中的成员

为了配合Vue的响应式数据,我们在Mutations的方法中,应当使用Vue提供的方法来进行操作。如果使用delete或者xx.xx = xx的形式去删或增,则Vue不能对数据进行实时响应。

Vue.set:为某个对象设置成员的值,若不存在则新增。如对state对象中添加一个age成员:
复制代码
Vue.set(state,"age",15)
Vue.delete:删除成员。如将刚刚添加的age成员删除:
复制代码
Vue.delete(state,'age')

2.3 Getters 对state中的成员进行筛选过滤

getters中的方法有两个默认参数:([state] , [getters])

  • state:当前VueX对象中的状态对象

  • getters:当前getters对象,用于将getters下的其他getter拿来用

在getters中自定义方法
复制代码
getters:{
    nameInfo(state){
        return "姓名:"+state.name
    },
    fullInfo(state,getters){
        return getters.nameInfo+'年龄:'+state.age
    }  
}
在组件中调用该方法
复制代码
this.$store.getters.fullInfo

2.4 Actions---异步操作

mutations只能处理同步函数,直接在mutation方法中进行异步操作,将会引起数据失效。所以提供了Actions来专门进行异步操作,最终提交mutation方法。actionsmutations的区别:
Actions提交的是 mutations,而不是直接变更状态。也就是说,actions会通过mutations,让mutations帮他提交数据的变更。
Action 可以包含任意异步操作。ajaxsetTimeoutsetInterval不在话下。

Actions中的方法有两个默认参数:([context] , [payload])

context:上下文(相当于箭头函数中的this)对象
payload:挂载参数

在actions中自定义异步方法:如在两秒中后执行edit方法(由于setTimeout是异步操作,所以需要使用actions)。
复制代码
actions:{
    edit(context,payload){
        setTimeout(()=>{
            context.commit('edit',payload)
        },2000)
    }
}
在组件中调用该异步方法
复制代码
this.$store.dispatch('edit',{age:15})

拓展:由于是异步操作,所以我们可以对异步操作封装为一个Promise对象,上面的异步方法可优化为:

复制代码
actions:{
    edit(context,payload){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                context.commit('edit',payload)
                resolve()
            },2000)
        })
    }
}

2.5 Modules

当项目庞大,状态非常多时,可以采用模块化管理模式。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 statemutationactiongetter、甚至是嵌套子模块------从上至下进行同样方式的分割。
复制代码
Modules :{
    a:{
        state:{},
        getters:{},
        ....
    }
}

组件内调用模块a的状态:

复制代码
this.$store.state.a

而提交或者dispatch某个方法和以前一样,会自动执行所有模块内的对应type的方法:

复制代码
this.$store.commit('editKey')
this.$store.dispatch('aEditKey')

2.5.1 模块的细节

模块中 mutationsgetters中的方法接受的第一个参数是自身局部模块内部的state

复制代码
Modules :{
    a:{
        state:{key:5},
        mutations:{
            editKey(state){
                state.key = 9
            }
        },
        ....
    }
}
  • getters中方法的第三个参数是根节点状态

    Modules :{
    a:{
    state:{key:5},
    getters:{
    getKeyCount(state,getter,rootState){
    return rootState.key + state.key
    }
    },
    ....
    }
    }

actions中方法获取局部模块状态是context.state,根节点状态是context.rootState

复制代码
Modules :{
    a:{
        state:{key:5},
        actions:{
            aEidtKey(context){
                if(context.state.key === context.rootState.key){
                    context.commit('editKey')
                }
            }
        },
        ....
    }
}

三、规范目录结构

如果把整个store都放在index.js中是不合理的,所以需要拆分。比较合适的目录格式如下:

复制代码
store:.
│  actions.js
│  getters.js
│  index.js
│  mutations.js
│  mutations_type.js   ##该项为存放mutaions方法常量的文件,按需要可加入
│
└─modules
        Astore.js

对应的内容存放在对应的文件中,和以前一样,在index.js中存放并导出storestate中的数据尽量放在index.js中。而modules中的Astore局部模块状态如果多的话也可以进行细分。

复制代码
// 假设你有如下的store模块
const moduleA = {
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
};
 
// 在store中注册模块
const store = new Vuex.Store({
  modules: {
    a: moduleA
  }
});
 
// 在组件中使用mapState获取模块状态
import { mapState } from 'vuex';
 
export default {
  computed: {
    // 使用对象展开运算符将此对象混入到外部对象中
    ...mapState({
      count: state => state.a.count // 这里的'a'是模块名,'count'是状态名
    })
  },
  methods: {
    increment() {
      this.$store.commit('a/increment'); // 使用模块名调用模块的mutation
    }
  }
};

最后编辑于:2025-06-15 09:52:43
© 著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务

喜欢的朋友记得点赞、收藏、关注哦!!!

相关推荐
计算机毕业设计小帅13 分钟前
【2026计算机毕业设计】基于Springboot的校园电动车短租平台
spring boot·后端·课程设计
superlls1 小时前
(Spring)Spring Boot 中 @Valid 与全局异常处理器的联系详解
java·spring boot·后端
勇敢di牛牛1 小时前
vue3 + mars3D 三分钟画一个地球
前端·vue.js
摇滚侠1 小时前
Spring Boot 3零基础教程,WEB 开发 整合 Thymeleaf 笔记36
java·spring boot·笔记
optimistic_chen2 小时前
【Java EE进阶 --- SpringBoot】Mybatis - plus 操作数据库
数据库·spring boot·笔记·java-ee·mybatis·mybatis-plus
来旺3 小时前
互联网大厂Java面试全解析及三轮问答专项
java·数据库·spring boot·安全·缓存·微服务·面试
摇滚侠3 小时前
Spring Boot 3零基础教程,yml文件中配置和类的属性绑定,笔记15
spring boot·redis·笔记
thginWalker3 小时前
使用Spring Boot构建消息通信层
spring boot
lang201509283 小时前
Spring Boot 外部化配置最佳实践指南
java·spring boot
我是日安4 小时前
从零到一打造 Vue3 响应式系统 Day 27 - toRef、toRefs、ProxyRef、unref
前端·javascript·vue.js