24.Vue状态管理Vuex

一、Vuex

Vuex是一个专为Vue.js应用程序开发的状态管理模式。

官网:https://next.vuex.vuejs.org/

主要功能:
  1. Vuex可以实现Vue不同组件之间的状态共享(解决了不同组件之间的数据共享)
  2. 可以实现组件里面的数据持久化

Vuex的几个核心概念

  • State 主要用于定义数据
  • Getters 与前面的计算属性类似,用于vuex中计算属性
  • Mutations 主要用于定义方法,改变state中的数据
  • Actions 主要用于执行Mutations的方法,用于异步操作
  • Modules

二、Vuex的基本使用

  1. 安装依赖

    npm install vuex@next --save
    # 或者
    yarn add vuex@next --save
    
  2. src目录下新建一个Vuex的目录,Vuex目录里面新建一个store.js

import {
     createStore} from 'vuex';
const store=createStore({
     
    state(){
     
        // 定义数据
        return{
     
            count:1
        }
    },
    mutations:{
     
        // 定义方法
        incCount(state){
     
            state.count++;
        }
    }
});

export default store;
  1. main.ts挂载store.js

    import {
           createApp} from 'vue'
    import App from '@/App.vue'
    import router from "@/router";// 引入router
    import store from "@/Vuex/store.js";
    
    const app = createApp(App);
    app.use(router);//挂载使用router
    app.use(store);// 挂载Vuex的store
    app.mount('#app')
    

三、Vuex中的State

  1. 第一种获取State的方法(不推荐)

    用到的组件里面引用store,然后计算属性里面获取 (单页面组件引用)

    computed:{
           
        count(){
           
            return store.state.count
        }
    }
    
  2. 第二种获取State的方法

    由于全局配置了Vuex app.use(store)。所以直接可以通过下面的方法获取store里面的值。

    computed:{
           
        count(){
           
            return this.$store.state.count
        }
    }
    

    获取store中的list

    <template>
        <ul>
            <li v-for="(item,index) in $store.state.list" :key="index">
                {
          {item}}
            li>
        ul>
    template>
    
  3. 第三中获取State的方法-通过mapState助手

    调用的组件中引入mapState

    import {
           mapState} from "vuex"
    
    • 方法1:store中的变量与组件中的变量名称不一致,使用箭头函数做映射

    • 方法2:store中的变量与组件中的变量名一样可以直接这样使用

    computed: {
           
        // 方法1
        ...mapState({
           
            thisCount: (state) => state.count,
            thisBanner: (state) => state.banner,
            thisList: (state) => state.list,
        }),
        //方法2
        ...mapState(["count","banner","list"])
    }
    

    在模板中调用:

    <template>
        <h3>mapState获取store中的数据(方法1)h3>
        thisCount:{
          { thisCount }}
        <br>
        thisBanner:{
          { thisBanner }}
        <br>
        <ul>
            <li v-for="(item,index) in thisList" :key="index">
                {
          { item }}
            li>
        ul>
        <hr>
        <h3>mapState获取store中的数据(方法2)h3>
        count:{
          { count }}
        <br>
        banner:{
          { banner }}
        <br>
        <ul>
            <li v-for="(item,index) in list" :key="index">
                {
          { item }}
            li>
        ul>
    template>
    

四、Vuex中的Getter

  1. 定义Getter

    const store = createStore({
           
        state() {
           
            // 数据
            return {
           
                count: 1,
                banner: "zws",
                list: ["文件", "编辑", "视图"],
                msg: "你好store"
            }
        },
        mutations: {
           
            // 方法,可以改变state里面的数据
            incCount(state) {
           
                state.count++;
            },
            setCount(state, num) {
           
                state.count += num;
            },
            setBanner(state) {
           
                state.banner = "改变后的banner"
            }
        },
        getters: {
           
            revMsg(state) {
           
                return state.msg.split("").reverse().join("");
            },
            num(state) {
           
                return state.count + 10;
            }
        }
    });
    
  2. 访问Getter的方法

    • 方法一:Getter会暴露为store.getter对象,你可以以属性的形式访问这些值:

      <template>
      	{
              {$store.getters.num}}
      template>
      
    • 方法二:使用计算属性

      computed:{
               
          count(){
               
              return this.$store.state.count
          },
          banner(){
               
              return this.$store.state.banner
          },
          revMsg(){
               
              return this.$store.getters.revMsg;
          },
          num(){
               
              return this.$store.getters.num;
          }
      }
      
    • 方法三:通过mapGetters辅助函数

      import {
               mapState,mapGetters} from "vuex"
      
      computed: {
               
          // 方法1
          ...mapState({
               
              thisCount: (state) => state.count,
              thisBanner: (state) => state.banner,
              thisList: (state) => state.list,
          }),
              //方法2
              ...mapState(["count","banner","list"]),
      
      
              // 使用对象展开运算符...mapGetters混入computed处对象中
              // 方法1
              ...mapGetters([
              "num","revMsg"
          ]),
              // 方法2
              // 给store中的getters取个别名
              ...mapGetters({
               
              thisMsg: "revMsg",
              thisNum: "num",
          }),
      }
      

      template中使用

      <template>
          <h3>mapGetters获取store中的getters(方法1)h3>
          revMsg:{
              {revMsg}}
          <br>
          num:{
              {num}}
          <br>
          <h3>mapGetters获取store中的getters(方法2)h3>
          revMsg:{
              {thisMsg}}
          <br>
          num:{
              {thisNum}}
      template>
      

五、Vuex中的Mutations

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

  1. 定义Mutations触发Mutations里面的方法

    const store=createStore({
           
        state(){
                  
            return{
           
                count:1
            }
        },
        mutations:{
                  
            incCount(state){
           
                 // mutate state
                state.count++;
            }
        }
    });
    

    触发mutations里面的方法:

    this.$store.commit('incCount')
    
  2. 执行方法传入参数:

    const store=createStore({
           
        state(){
           
            // 数据
            return{
           
                count:1,
                myname:"zws"
            }
        },
        mutations:{
           
            // 方法,可以改变state里面的数据
            incCount(state){
           
                state.count++;
            },
            setCount(state,num){
           
                state.count+=num;
            },
            setMyName(state){
           
                state.myname="改变后的zws"
            }
        }
    });
    

    触发方法:

    this.$store.commit("setCount",15);
    

六、Vuex中的Actions

  1. store.js中定义Actions

    const store = createStore({
           
        state() {
           
            // 数据
            return {
           
                count: 1,
                banner: "zws",
                list: ["文件", "编辑", "视图"],
                msg: "你好store"
            }
        },
        mutations: {
           
            // 方法,可以改变state里面的数据
            incCount(state) {
           
                state.count++;
            },
            setCount(state, num) {
           
                state.count += num;
            },
            setBanner(state, msg) {
           
                state.banner = "改变后的banner" + msg;
            }
        },
        getters: {
           
            revMsg(state) {
           
                return state.msg.split("").reverse().join("");
            },
            num(state) {
           
                return state.count + 10;
            }
        },
        actions: {
           
            // 主要用于执行Mutations里面的方法,异步操作放在这里
            inCount(context) {
           
                // 执行mutations里面的incCount方法
                context.commit("incCount");
            },
            incSetBanner(context,msg) {
           
                setTimeout(() => {
           
                    context.commit("setBanner", msg);
                }, 1000);
            },        
            // 另一种写法
            /*incSetBanner({commit},msg) {
                setTimeout(() => {
                    commit("setBanner", msg);
                }, 1000);
            },*/
        }
    });
    
  2. 触发Actions中的方法

    store.dispatch("inCount");
    store.dispatch("incSetBanner","zws");
    

    乍一眼看上去感觉多此一举,我们直接分发mutations岂不是更方便?实际上并非如此,还记得mutations必须同步执行这个限制么?Actions就不受约束~!我们可以在actions内部执行异步操作

七、Vuex中的Modules

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。

为了解决以上问题,Vuex允许我们将store分割成模块(Modules)。每个模块拥有自己的state,mutations,actions,getters,甚至是嵌套子模块——从上至下进行同样的方式分割:

const moduleA = {
     
  state: () => ({
      ... }),
  mutations: {
      ... },
  actions: {
      ... },
  getters: {
      ... }
}

const moduleB = {
     
  state: () => ({
      ... }),
  mutations: {
      ... },
  actions: {
      ... }
}

const store = createStore({
     
  modules: {
     
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state

示例:

在Vuex目录新建userStore.js

let userStore = {
     
    state() {
     
        // 数据
        return {
     
            count: 1,
            banner: "zws",
            msg: "你好store"
        }
    },
    mutations: {
     
        // 方法,可以改变state里面的数据
        incCount(state) {
     
            state.count++;
        },
        setCount(state, num) {
     
            state.count += num;
        },
        setBanner(state, msg) {
     
            state.banner = "改变后的banner" + msg;
        }
    },
    getters: {
     
        revMsg(state) {
     
            return state.msg.split("").reverse().join("");
        },
        num(state) {
     
            return state.count + 10;
        }
    },
    actions: {
     
        // 主要用于执行Mutations里面的方法,异步操作放在这里
        inCount(context) {
     
            // 执行mutations里面的incCount方法
            context.commit("incCount");
        },
        incSetBanner(context, msg) {
     
            setTimeout(() => {
     
                context.commit("setBanner", msg);
            }, 1000);
        },
    }
}
export default userStore;

在Vuex目录新建newsStore.js

let newsStore = {
     
    state() {
     
        // 数据
        return {
     
            list: ["新闻1", "新闻2", "新闻3"],
            count: 100
        }
    },
    mutations: {
     
        incCount(state) {
     
            state.count++;
        }
    }
}
export default newsStore;

改造store.js

import {
     createStore} from 'vuex';
import userStore from '@/Vuex/userStore';
import newsStore from "@/Vuex/newsStore";

const store = createStore({
     
    modules:{
     
        "user":userStore,
        "news":newsStore
    }
});
export default store;

在User.vue组件中使用userStore与newsStore的state数据与调用mutations里面的方法

<template>
    <div>
        <h1>User组件h1>
        获取userStore里面的count:{
    {$store.state.user.count}}
        <br>
        获取newsStore里面的count:{
    {$store.state.news.count}}
        获取newsStore里面的list:
        <ul>
            <li v-for="(item,index) in list" :key="index">
                {
    {item}}
            li>
        ul>
        <br>
        <br>
        <button @click="incCount">调用mutations里面的方法button>
    div>

template>

<script>
    import {
      defineComponent} from "vue";

    export default defineComponent({
      
        setup() {
      
            return {
      }
        },
        computed:{
      
            list(){
      
                return this.$store.state.news.list;
            }
        },
        methods:{
      
            incCount(){
      
                // 调用mutations里面的方法
                // 广播:userStore与newsStore里面的incCount都会执行
                this.$store.commit("incCount");
            }
        }
    });
script>

注意:如果多个store模块中定义有相同的方法名,调用的时候,都会被调用

你可能感兴趣的:(Vue3学习笔记,vue)