Vue 状态管理 Vuex

Vue 状态管理 Vuex

官网文档:https://vuex.vuejs.org/zh/

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

Vuex 的简单理解

  • Vue 应用中的每一个组件在 data() 中封装自己的数据属性,而这些 data 属性是私有的,完全隔离的。
  • 如果我们希望多个组件都能读取到同一个状态数据属性,或者不同的组件的行为需要更新同一状态数据属性,这就需要一个将共享的状态数据属性进行集中式的管理。
  • 这就是 Vuex 状态管理所要解决的问题。

安装依赖

npm install --save vuex

在这里插入图片描述

使用Vuex

创建文件

在项目 src 文件夹下创建一个 store 文件夹,存储状态,将所有的状态存储到这个文件夹里面。在 store 文件夹下创建一个 index.js 文件。
在这里插入图片描述

创建Vuex对象

在 index.js 文件中编写 Vuex 对象并导出。

在状态中存储一个 count 值为 1。

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

// 引入 Vuex 插件
Vue.use(Vuex)

// 创建一个仓库,用来存储对应的状态
const store = new Vuex.Store({
    
    
    state: {
    
     // 存放状态(共享的属性)
        count: 1
    }  
})

// 导出Vuex对象
export default store

将 Vuex 注册到 vue实例当中

在 main.js 文件中注册 Vuex。

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
// 导入 vuex,默认导入的是 ./store/index.js
import store from './store'

Vue.config.productionTip = false;

new Vue({
    
    
  router,
  store, // 注册
  render: h => h(App)
}).$mount("#app");

获取状态 count 值

获取状态值得方式是 $store.state.状态名。

 $store.state.xxx

在组件中使用:

<template>
  <div class="home">
     count:{
    
    {
    
     $store.state.count }}
  </div>
</template>

<script>

export default {
    
    
  name: "Home",
};
</script>

在这里插入图片描述

更改状态值

  1. 在 store 的 mutations 选项中定义方法,才可以改变状态值。
  2. 在通过 $store.commit(“mutationName”) 触发状态值的改变。

创建一个修改 count 值得方法,在 index.js 文件中,添加一个增加的方法,修改 state 对象中的 count 值。

mutations: {
    
    
        // 增加的方法,改变state的状态值
        increment(state) {
    
    
            state.count ++ 
        }
    }

在这里插入图片描述

在组件中创建一个按钮,点击按钮,是的状态值 count 自增。

<template>
  <div class="home">
    <p>count:{
    
    {
    
     $store.state.count }}</p>
    <button @click="addCount">count 自加</button>
  </div>
</template>

<script>
export default {
    
    
  name: "Home",
  methods: {
    
    
    addCount() {
    
    
      // 现获取状态值
      console.log(this.$store.state.count);
      // 修改 count 值
      this.$store.commit('increment')
    }
  }
};
</script>

在这里插入图片描述
改变状态值 count 的方法就实现了。

在写一个自减哈,闲着也是闲着,做法和自加是一样的

index.js文件中:

mutations: {
    
    
        // 增加的方法,改变state的状态值
        increment(state) {
    
    
            state.count ++ 
        },
        // 自减
        decrement(state) {
    
    
            state.count -- 
        }
    }

组件:

<template>
  <div class="home">
    <p>count:{
    
    {
    
     $store.state.count }}</p>
    <button @click="addCount">count 自加</button>
    <button @click="decrement">count 自减</button>
  </div>
</template>

<script>
export default {
    
    
  name: "Home",
  methods: {
    
    
    addCount() {
    
    
      // 现获取状态值
      console.log(this.$store.state.count);
      // 修改 count 值
      this.$store.commit('increment')
    },
    decrement() {
    
    
      // 现获取状态值
      console.log(this.$store.state.count);
      // 修改 count 值
      this.$store.commit('decrement')
    }
  }
};
</script>

在这里插入图片描述
任意组件,都可以获取到状态值,数据是共享的,当一个地方改变了状态的值,所有的地方都可以获取到最新状态值。

提交载荷

就是向 $store.commit 中提交额外的参数,即 mutation 的载荷 (payload)。

例如:修改自加功能,增加的时候传进一个参数 n,是 count 加上传进来的 n。修改 index.js 文件自加方法:

mutations: {
    
    
    // 增加的方法,改变state的状态值
    increment(state, n) {
    
      // n 为载荷
        state.count += n   // state.count = state.count + n
    },
    // 自减
    decrement(state) {
    
    
        state.count -- 
    }
}

在这里插入图片描述

修改组件方法:

addCount() {
    
    
      // 现获取状态值
      console.log(this.$store.state.count);
      // 修改 count 值
      // this.$store.commit('increment')
      this.$store.commit('increment', 10)
},

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

Action的作用和使用

Action 类似于 mutation,但不同点在于:

  1. Action 提交的是 mutation,而不是在组件中直接变更状态,通过他间接更新 state。
  2. 在组件中通过 this.$store.dispatch(‘actionName’) 触发状态值间的改变。
  3. Action 也支持载荷。
  4. Action 可以包含任意异步操作。

修改 index.js 文件,添加 actions 。

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

// 引入 Vuex 插件
Vue.use(Vuex)

// 创建一个仓库,用来存储对应的状态
const store = new Vuex.Store({
    
    
    state: {
    
     // 存放状态(共享的属性)
        count: 1
    },
    mutations: {
    
    
        // 增加的方法,改变state的状态值
        increment(state, n) {
    
      // n 为载荷
            state.count += n   // state.count = state.count + n
        },
        // 自减
        decrement(state) {
    
    
            state.count--
        }
    },
    actions: {
    
    
        add(context) {
    
    
            // 触发 mutations 中的 increment 来改变 state
            context.commit('increment', 10)
        }
    }
})

// 导出Vuex对象
export default store

修改组件,点击自加按钮时候的逻辑:

addCount() {
    
    
      // 现获取状态值
      console.log(this.$store.state.count);
      // 修改 count 值
      // this.$store.commit('increment')
      // this.$store.commit('increment', 10)
      // 触发 action 修改 state
      this.$store.dispatch('add')
   },

在这里插入图片描述
action 也可以实现载荷

actions: {
    
    
        add(context, n) {
    
    
            // 触发 mutations 中的 increment 来改变 state
            context.commit('increment', n)
        }
 }
addCount() {
    
    
      // 现获取状态值
      console.log(this.$store.state.count);
      // 修改 count 值
      // this.$store.commit('increment')
      // this.$store.commit('increment', 10)
      // 触发 action 修改 state
      this.$store.dispatch('add', 10)
    },

在这里插入图片描述
效果一样!

action 还有其他的提交方式

比如修改减法

actions: {
    
    
        add(context, n) {
    
    
            // 触发 mutations 中的 increment 来改变 state
            context.commit('increment', n)
        },
        // 参数是一个对象,commit就是提交,state就是状态对象,按需传入
        decrement({
    
    commit,state}) {
    
    
            console.log('actions.decrement.state.count ',state.count)
            commit('decrement')
        }
    }

组件调用减法:

decrement() {
    
    
      // 现获取状态值
      // console.log(this.$store.state.count);
      // 修改 count 值
      // this.$store.commit('decrement')
      this.$store.dispatch('decrement')
}

派生属性 getter

  1. 有时候哈,我们需要从 store 中的 state 中派生出一些状态。就比如说哈,基于上面的那个代码,增加一个 desc 属性,当那个 count 小于50的时候,desc 的值就是“吃饭饭”,大于等于50小于100,desc 的值就是 “睡觉觉”,当 count 的值大于100,desc 的值就是“打豆豆”。这个时候,我们就需要使用 getter 为我们解决问题了。
  2. getter 其实就是一个类似于计算属性(get)的对象。
  3. 组件中读取 $store.getter.xxx

修改 index.js 文件,增加 getters 选项:

getters: {
    
     // 定义派生属性
    desc(state) {
    
      // 类似于计算属性的个玩意儿,会监听count值
        // 这个state就是上面的state,他会自动的传进来
        if(state.count < 50){
    
    
            return '吃饭'
        } else if (state.count < 100){
    
    
            return '睡觉'
        } else {
    
    
            return '打豆豆'
        }
    }
}

在这里插入图片描述
修改组件,测试派生desc

<p>派生属性 desc 测试:{
    
    {
    
     $store.getters.desc }}</p>

在这里插入图片描述
效果就是下面的样子啦:
在这里插入图片描述

Vuex 模块化 Module 管理

随着状态值得增加,对状态值操作的增加,index.js 文件会变得越来约大,越来越臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module),每个模块有自己的 state、mutation、action、getter 等。

结构大体就是下面的样子:

const moduleA = {
    
    
  state: {
    
    },
  mutations: {
    
    },
  actions: {
    
    },
  getters: {
    
    }
}

const moduleB = {
    
    
  state: {
    
    },
  mutations: {
    
    },
  actions: {
    
    }
}
const store = new Vuex.Store({
    
    
  modules:{
    
    
    a:modeuleA,
    b:modulesB
  }
})

store.state.a  // modelA 的状态
store.state.b  // modelB 的状态

模块化之前代码

index.js 文件

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

// 引入 Vuex 插件
Vue.use(Vuex)

// 将 home 相关的状态抽取为一个模块
const home = {
    
    
    state: {
    
     // 存放状态(共享的属性)
        count: 1
    },
    mutations: {
    
    
        // 增加的方法,改变state的状态值
        increment(state, n) {
    
      // n 为载荷
            state.count += n   // state.count = state.count + n
        },
        // 自减
        decrement(state) {
    
    
            state.count--
        }
    },
    actions: {
    
    
        add(context, n) {
    
    
            // 触发 mutations 中的 increment 来改变 state
            context.commit('increment', n)
        },
        // 参数是一个对象,commit就是提交,state就是状态对象
        decrement({
    
    commit,state}) {
    
    
            console.log('actions.decrement.state.count ',state.count)
            commit('decrement')
        }
    },
    getters: {
    
     // 定义派生属性
        desc(state) {
    
      // 类似于计算属性的个玩意儿,会监听count值
            // 这个state就是上面的state,他会自动的传进来
            if(state.count < 50){
    
    
                return '吃饭'
            } else if (state.count < 100){
    
    
                return '睡觉'
            } else {
    
    
                return '打豆豆'
            }
        }
    }
}

// 将 goods 相关的状态抽取为一个模块
const goods = {
    
    
    state: {
    
    },
    mutations: {
    
    },
    actions: {
    
    },
    getters: {
    
    }
}

// 创建一个仓库,用来存储对应的状态
const store = new Vuex.Store({
    
    
    modules: {
    
    
        home,   // home: home
        goods,
    }
})

// 导出Vuex对象
export default store

组件代码

<template>
  <div class="home">
    <!-- <p>count:{
    
    {
    
     $store.state.count }}</p> -->  <!--  模块话之前 -->
    <p>count:{
    
    {
    
     $store.state.home.count }}</p>  <!--  模块话之后 -->
    <button @click="addCount">count 自加</button>
    <button @click="decrement">count 自减</button>
    <p>派生属性 desc 测试:{
    
    {
    
     $store.getters.desc }}</p>
  </div>
</template>

<script>
export default {
    
    
  name: "Home",
  methods: {
    
    
    addCount() {
    
    
      // 现获取状态值
      // console.log(this.$store.state.count);  // 模块化钱前
      console.log(this.$store.state.home.count);  // 模块化后
      // 修改 count 值
      // this.$store.commit('increment')
      // this.$store.commit('increment', 10)
      // 触发 action 修改 state
      this.$store.dispatch('add', 10)
    },
    decrement() {
    
    
      // 现获取状态值
      // console.log(this.$store.state.count);
      // 修改 count 值
      // this.$store.commit('decrement')
      this.$store.dispatch('decrement')
    }
  }
};
</script>

在这里插入图片描述
一样的效果!完美~!

基于 Vuex 标准项目结构重构项目

如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。所以最好把每一部分都单独抽成一个 js 文件。

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。

  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。

  3. 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
在这里插入图片描述

注意! Vuex 的状态值在所有组件共享,在路由切换的时候状态值会得到保存,但是!在刷新整个页面之后,状态值会重置,这个是后如果想保留状态值,能且只能与 localStorage 进行配合。

【相关代码:https://gitee.com/wjw1014/vue_learning_vuex

猜你喜欢

转载自blog.csdn.net/weixin_42776111/article/details/107661662