• 【Vuex】vue状态机详解


    目录

    Vuex

    1、Vuex的五个属性

    2、Vuex工作原理

    3、Vuex的使用

    在html文件中使用

    辅助函数

    模块化modules和命名空间namespaced

    在vue-cli脚手架中使用


    Vuex

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    Vuex是一个状态管理模式,也叫状态机,将组件共享的数据放到状态机中统一管理,组件想拿数据可以从自己的数据模型中拿,也可以从仓库中拿,可以把vuex理解成一个仓库。

    假设A组件想要拿B组件里面的数据,那就把A组件和B组件的数据放到Vuex中,A组件想要获取B组件数据从vuex中拿,B组件想要获取A组件的数据也从Vuex拿。

    1、Vuex的五个属性

    1. {
    2. //state 维护的是公共状态(数据),类似Vue中的data
    3. state: {},
    4. //getters 处理state中的数据并返回新数据,类似计算属性computed
    5. getters: {},
    6. //mutations 突变,修改state的唯一方式,只能做同步操作
    7. mutations: {},
    8. //actions 动作,处理异步操作,获取后台响应,提交数据给突变mutations
    9. actions: {},
    10. // 状态机可以有多个,modules用来存放各模块的状态机
    11. modules: {}
    12. }

    2、Vuex工作原理

    vuex三个主要的属性:state、mutations、actions


     

    当我们声明了一个状态机并将其注入Vue实例中,那么Vue实例上就会存在一个$store属性,该属性上有dispatch和commit等方法。 

    分析上图:

    Vue组件将需要执行的方法通过dispatch方法派发给Actions执行,但是Actions不会去执行该方法,于是它又通过commit方法提交该方法给Mutation来执行,Mutation执行完后,将处理完的数据给State,然后State重新渲染数据到页面。

    注意:当Vue组件需要操作的数据不需要通过网络请求得到时,可以跳过actions,直接使用commit方法提交给mutations处理。

    3、Vuex的使用

    在html文件中使用

    1、通过CDN引入Vuex

    Vuex是Vue的一个插件,使用时需要安装

    <script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.6.0/vuex.min.js" integrity="sha512-uN93RUcJ9frHH6dyLknjgalFe7JNkfb3OjW4Qgg5xjaVA3U7l0diZ3hGL2Puk/38sp7xD/SLHdNFit7Kq3RbtQ==" crossorigin="anonymous" referrerpolicy="no-referrer">script>
    

    2、声明状态机

    1. let store = new Vuex.Store(
    2. {
    3. //state 维护的是公共状态,类似Vue中的data
    4. state: {},
    5. //getters 处理state中的数据并返回新数据,类似计算属性computed
    6. getters: {},
    7. //mutations 突变,修改state的唯一方式,只能做同步操作
    8. mutations: {},
    9. //actions 动作,处理异步操作,获取后台响应,提交数据给突变mutations
    10. actions: {}
    11. }
    12. )

    3、将状态机注入Vue实例

    1. let vm = new Vue({
    2. // 将状态机注入Vue实例
    3. store,
    4. el: "#app",
    5. data: {}
    6. })

    此时可以打印Vue实例中的$store看一下:

    console.log(vm.$store)

     因此我们可以在插值语法中使用 $store.state.xxx 和 $store.getters.xxx 访问state中的数据和getters中的方法。

    例子:

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Documenttitle>
    8. <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10">script>
    9. <script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.6.0/vuex.min.js" integrity="sha512-uN93RUcJ9frHH6dyLknjgalFe7JNkfb3OjW4Qgg5xjaVA3U7l0diZ3hGL2Puk/38sp7xD/SLHdNFit7Kq3RbtQ==" crossorigin="anonymous" referrerpolicy="no-referrer">script>
    10. head>
    11. <body>
    12. <div id="app">
    13. {{$store.state.msg}}
    14. {{$store.getters.MSG}}
    15. <hr>
    16. {{$store.state.sum}}
    17. <button @click="foo">点击加{{n}}button>
    18. div>
    19. <script>
    20. let store = new Vuex.Store({
    21. state: {
    22. msg: 'hello',
    23. sum: 0
    24. },
    25. // getters用来处理state中的数据
    26. getters: {
    27. MSG(state){ //默认有一个参数,它是一个对象,里面存放了state中的数据
    28. // console.log(state);
    29. return state.msg.toUpperCase()
    30. }
    31. },
    32. actions: {
    33. // 默认有两个参数:sto是一个类状态机对象; value是dispatch传递过来的数据
    34. add(sto, value){
    35. // console.log(sto, value, 'actions');
    36. // 提交突变给mutations
    37. // commit('mutations中的方法名', 需要传递的数据)
    38. sto.commit('ADD', value)
    39. }
    40. },
    41. mutations: {
    42. // 最终在mutations中处理数据
    43. // 默认两个参数:state是一个对象,里面存放了state中的数据; value是commit提交的时候传递过来的数据
    44. ADD(state, value){
    45. // console.log(state, value, 'mutations');
    46. state.sum += value
    47. }
    48. },
    49. })
    50. let vm = new Vue({
    51. store,
    52. el: "#app",
    53. data: {
    54. n: 2
    55. },
    56. methods:{
    57. foo(){
    58. // 派发一个动作给actions
    59. // dispatch('actions中的方法名', 需要传递的数据)
    60. this.$store.dispatch('add', this.n)
    61. }
    62. }
    63. })
    64. // console.log(vm); //打印Vue实例,可以看到Vue实例上有一个$store属性
    65. script>
    66. body>
    67. html>

    辅助函数

    Vuex提供的组件辅助函数有mapState、mapGetters、mapActions、mapMutations,它们存在Vuex对象上,使用时可以使用Vuex.mapState的方式调用,也可以将它们从Vuex中解构出来使用:

    let { mapState, mapGetters, mapActions, mapMutations } = Vuex

    1、mapState方法:用于帮助映射 state 中的数据为计算属性

    1. computed:{
    2. // msg(){
    3. // return this.$store.state.msg
    4. // },
    5. // sum(){
    6. // return this.$store.state.sum
    7. // }
    8. //-----------------------------------------------------
    9. // 借助mapState函数生成上述计算属性
    10. // mapState返回一个对象,我们需要使用扩展运算符将它们展开
    11. // 1、对象写法
    12. ...mapState({msg:'msg',sum:'sum'})
    13. // 2、数组写法
    14. ...mapState(['msg','sum'])
    15. },
    16. // 测试,看一下mapState返回值
    17. created(){
    18. let a = mapState({msg:'msg',sum:'sum'})
    19. console.log(a); //返回一个对象,对象中有msg、sum方法
    20. },

    使用了mapState方法之后,我们在插值语法直接使用{{msg}}、{{sum}}即可,不需要写成:{{$store.state.msg}}、{{$store.state.sum}},同理mapGetters方法也一样。

    2、mapGetters方法:用于帮助映射 getters 中的数据为计算属性

    1. computed:{
    2. // MSG(){
    3. // return this.$store.getters.MSG
    4. // }
    5. //------------------------------------------------------
    6. // 借助mapGetters函数生成上述计算属性
    7. // 1、对象写法
    8. ...mapGetters({MSG:'MSG'})
    9. // 2、数组写法
    10. ...mapGetters(['MSG'])
    11. },

    3、mapActions方法:用于帮助生成与 actions 对话的方法,即包含$store.dispatch(xxx)的函数

    1. methods:{
    2. // foo(){
    3. // this.$store.dispatch('add', this.n)
    4. // }
    5. //--------------------------------------------
    6. // 借助mapActions函数生成上述foo方法
    7. // mapActions返回一个对象,我们需要使用扩展运算符将它们展开
    8. // 1、对象写法
    9. ...mapActions({foo:'add'}),
    10. // 2、数组写法 (注意:需要对象的属性名和属性值一样才能写成下面的数组形式)
    11. ...mapActions(['foo'])
    12. }

    4、mapMutations方法:用于帮助生成与 mutations 对话的方法,即包含$store.commit(xxx)的函数

    1. methods:{
    2. // foo(){
    3. // this.$store.commit('ADD', this.n)
    4. // }
    5. //--------------------------------------------
    6. // 借助mapMutations函数生成上述foo方法
    7. // mapMutations返回一个对象,我们需要使用扩展运算符将它们展开
    8. // 1、对象写法
    9. ...mapMutations({foo:'ADD'}),
    10. // 2、数组写法 (注意:需要对象的属性名和属性值一样才能写成下面的数组形式)
    11. ...mapMutations(['foo'])
    12. }

    注意:使用 mapActions 和 mapMutations 时,若需要传递参数,那么参数要在模板绑定事件的时候传参。

    <button @click="foo(n)">点击加{{n}}button>

    模块化modules和命名空间namespaced

    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块,每个模块拥有自己的 state、mutation、action、getter,甚至是嵌套子模块。namespaced表示设置命名空间。

    Vuex中的modules属性用来存放各个模块的状态机。

    1. let aModule = {
    2. // 开启命名空间
    3. namespaced: true,
    4. state:{},
    5. getters:{},
    6. actions:{},
    7. mutations:{}
    8. }
    9. let bModule = {
    10. namespaced: true,
    11. state:{},
    12. getters:{},
    13. actions:{},
    14. mutations:{}
    15. }
    16. let store = new Vuex.Store({
    17. modules:{
    18. a:aModule,
    19. b:bModules
    20. }
    21. })

    (1)组件中读取state中数据 

    1. // 方式一:自己读取
    2. this.$store.state.a.xxx
    3. // 方式二:使用mapState读取 表示后面数组里面的属性是a模块的
    4. ...mapState('a',['xxx1','xxx2','xxx3'])

     (2)组件中读取getters中的数据

    1. // 方式一:自己读取
    2. this.$store.getters['a/xxx']
    3. // 方式二:使用mapGetters读取 表示后面数组里面的属性是a模块的
    4. ...mapGetters('a',['xxx1','xxx2','xxx3'])

    (3)组件中调用dispatch

    1. // 方式一:自己直接dispatch
    2. this.$store.dispatch('a/xxx',需要传递的数据)
    3. // 方式二:使用mapActions读取
    4. ...mapActions('a',['xxx1','xxx2','xxx3'])

    (4)组件中调用commit

    1. // 方式一:自己直接commit
    2. this.$store.commit('a/xxx',需要传递的数据)
    3. // 方式二:使用mapMutations读取
    4. ...mapMutations('a',['xxx1','xxx2','xxx3'])

    vue-cli脚手架中使用

    写个小案例:当我们点击登录的时候会获取到一个token值,这个token值其他组件也需要使用,因此我们可以把token值存在vuex中,供所有的组件使用。

    1、安装vuex

    注意:vuex4版本以上只能在vue3中使用,vue2使用vuex3版本,安装时如果不指定版本,会安装最新版本的vuex

    npm i vuex@3.6.2

    2、在src下新建一个文件夹store,然后在store文件夹下再新建一个文件夹login,存放登录相关的状态机

    src/store/index.js 

    1. import Vue from 'vue';
    2. import Vuex from 'vuex';
    3. // 引入登录状态机
    4. import login from '../store/login/login';
    5. Vue.use(Vuex);
    6. export default new Vuex.Store({
    7. state:{},
    8. getters:{},
    9. mutations:{},
    10. actions:{},
    11. modules:{
    12. login
    13. }
    14. })

    src/login/login.js

    1. import axios from 'axios';
    2. // 这是我登录状态机配置对象
    3. export default {
    4. // 开启命名空间
    5. namespaced: true,
    6. state: {
    7. token: localStorage.getItem('token') || ""
    8. },
    9. gettes: {},
    10. mutations: {
    11. SET_TOKEN(state, payload) {
    12. state.token = payload;
    13. // 持久化储存
    14. localStorage.setItem('token', payload)
    15. }
    16. },
    17. actions: {
    18. async login({commit}, payload) {
    19. // 发送异步请求
    20. let res = await axios.post('登录接口地址', payload)
    21. // console.log(res);
    22. commit('SET_TOKEN', res.data.data.token)
    23. }
    24. }
    25. }

    3、在src下新建文件夹pages,存放组件

    login.vue

    1. <script>
    2. import {mapActions} from 'vuex'
    3. export default {
    4. data(){
    5. return {
    6. obj:{
    7. username:"xxx",
    8. password:xxx
    9. }
    10. }
    11. },
    12. methods:{
    13. // 分发状态机动作 发送登录请求
    14. ...mapActions('login',['login'])
    15. }
    16. }
    17. script>

     user.vue

    1. <script>
    2. import {mapState} from 'vuex';
    3. export default {
    4. data(){
    5. return {}
    6. },
    7. computed:{
    8. ...mapState('login',['token'])
    9. }
    10. }
    11. script>

     

  • 相关阅读:
    深度神经网络之BiseNet
    线扫相机——机器视觉中无限制物体的检测(重要转载)
    FEDformer
    利用canvas实现根据背景图片主色调动态展示字体颜色
    软件配置 | Git下载、安装及卸载
    RCU501 RMP201-8 KONGSBERG 分布式处理单元
    针对Office宏病毒的高级检测
    【代码随想录01】数组总结
    产品说明丨如何使用MobPush快速创建应用
    【GD32F427开发板试用】IAR flash loader 下载GD32F427流程简要分析
  • 原文地址:https://blog.csdn.net/lq313131/article/details/127131901