Vuex 状态管理的基本使用配置

vuex流程图

1.安装Vue 依赖包

npm install vuex@3 --save
vue2 只能用vuex的3版本
vue3 只能用vuex的4版本
npm view vuex versions 查看vuex所有版本

2.创建 store

src目录下 新建 store 目录 ,创建 index.js 文件

// 引入 vue
import Vue from 'vue'

// 引入 vuex
import Vuex from 'vuex'

// 使用Vuex
Vue.use(Vuex)

// 用于存储数据
const state = {}

// 用于响应组件中的动作
const actions = {}

// 用于操作数据(state)
const mutations = {}

// 创建store
const store = new Vuex.Store({
    state,
    mutations,
    actions
})

// 导出 store
export default store;

3.引入store

main.js 中 引入 import store from './store'
配置 store

new Vue({
   el: '#app',
   render:h => h(App),
   router,
   //将创建的共享数据对象,挂载在vue实例中
   //所有的组件,就可以直接从store中获取全局的数据了
   store
})

Vuex 应用

state

作用:获取数据

获取state数据的第一种方式

this.$store.state.全局数据名称

第二种方式

从vuex中按需导入mapState 函数

import { mapState } from 'vuex'

通过刚才导入的mapState 函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性

computed: { 
   //数组写法  count 是store中全局共享数据名称   获取store中的数据
    ...mapState(['count'])
   // 对象写法
   ...mapState({count:'count',...})
}

mutations

作用:修改全局state中的数据(用于操作数据)

只能 通过 mutations 修改 state 中的数据,可以集中监控所有数据的变化。不可以直接操作 store 中的数据。
mutations里面方法名称一般大写,方法第一个参数永远都是一个 state 代表全局对象,直接state.属性就可以调用全局共享数据的属性,

const mutations = { 
    // value 参数
    INCRE(state, value) {
        state.sum += value
    },

    DECRE(state, value) {
        state.sum -= value
    }
}

触发mutation 的第一种方式

不传参数:this.$store.commit('方法名') add 是Mutation中定义的函数名
传参数 : this.$store.commit('方法名',参数)

触发mutation 的第二种方式
vuex 中按需导入 mapMutations 函数

import { mapMutations } from 'vuex'

通过刚才导入的 mapMutations 函数,将需要的 mutations,映射为当前组件的 methods 方法

 methods: {
    // 数组写法   吧全局mutations里面的sub、subN函数映射为当前组件的methods (如果有参数需要触发的时候传过来)
    ...mapMutations(['sub', 'subN']), 
    // 对象写法 (如果有参数需要触发的时候传过来)
    ...mapMutations({sub:'sub', subN:'subN'}), 
 }
    
 this.sub();//可以直接调用
 this.subN();//可以直接调用

注意:在 mutations 中不要执行异步操作,mutations里面只处理简单方法,没有业务逻辑的

actions

作用:用于处理异步任务

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

action方法第一个参数永远都是一个 context 相当于new出来的 store 的实体对象

修改state中的数据必须通过 mutations

触发Actions 的第一种方式

this.$store.dispatch('方法名')  //addAsync adction中的函数  dispatch函数 专门用来触发 action

触发Actions 的第二种方式
从vuex中按需导入 mapActions 函数

import { mapActions } from 'vuex'

通过刚才导入的 mapActions 函数,将需要的 actions 函数 ,映射为当前组件的methods方法

 methods: {
    // 数组方式 (方法名称必须和vuex里面的方法相同)
    ...mapActions(['方法名1', '方法名2'])
    // 对象方式
    ...mapActions({ 方法名1: 'action里面的方法名1',方法名2: 'action里面的方法名2' })
 }

getters

作用: 包装作用,不会修改数据(用于 state 中数据加工)

在getters中定义一个函数

//定义函数
showNum(state) {
    return '当前最新数据是[' + state.count + ']'
}

使用getters第一种方式

this.$store.getters.名称
this.$store.getters.showNum

使用getters第二种方式

从vuex中按需导入 mapGetters 函数

//组件访问state中数据的第二种方式 先导入
import { mapGetters } from 'vuex';

通过刚才导入的mapGetters函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性

 computed: { 
    // 数组写法(方法名称必须和vuex里面的方法相同)
    ...mapGetters(['方法名']),
    // 对象写法
    ...mapGetters({ 方法名: 'getter里面的方法名称' })
  }

vuex 模块化+命名空间

目的:代码更好维护,让多种类数据更加明确

开启命名空间后,读取 state 数据

this.$store.state.countAbout.sum  // 直接的读取
...mapState('countAbout', ["sum", "school", "subject"]) // 借助mapState读取

开启命名空间后,读取 getters 数据

this.$store.getters[countAbout/bigSum] // 直接的读取
...mapGetters('countAbout', ['bigSum']) //借助mapGetters读取

开启命名空间后,读取 dispatch 数据

this.$store.dispatch('countAbout/increOdd', val) // 直接的读取
...mapActions('countAbout', { handleIncreOdd: 'increOdd', handleIncreWait: 'increWait' }) // 借助 mapActions 读取

开启命名空间后,读取 commit 数据

this.$store.commit('countAbout/INCRE', val) // 直接的读取
...mapMutations('countAbout', { handleIncre: 'INCRE', handleDecre: 'DECRE' }) // 借助 mapMutations 读取

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

import countOptions from "./modules/count"
import personOptions from "./modules/person"

// 创建store并导出 store
export default new Vuex.Store({
    modules: {
        countAbout: countOptions,
        personAbout: personOptions
    }
})

store/modules/count.js

count.js

Demo1 ==> 计数

Count.vue

<template>
  <div>
    {{sum}}
    <p>getters:{{bigSum}}</p>
    <p> {{school}}, {{subject}}</p>
    <button @click="handleIncre(2)">+2</button>
    <button @click="handleDecre(3)">-3</button>
    <button @click="handleIncreOdd(1)">奇数加1</button>
    <button @click="handleIncreWait(1)">1s后+1</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex"
export default {
  computed: {

    // sum() {
    //   return this.$store.state.sum
    // },

    // ...mapGetters(['bigSum']),//数组写法
    ...mapGetters({ bigSum: 'bigSum' }), // 对象写法

    // ...mapState(["sum", "school", "subject"])  //数组写法
    ...mapState({ sum: "sum", school: "school", subject: "subject" })  // 对象写法

  },
  methods: {
    // 写法一
    // handleIncre(val) {
    //   this.$store.commit('INCRE', val)
    // },
    // handleDecre(val) {
    //   this.$store.commit('DECRE', val)
    // },

    // 写法二:简写形式,参数需要从方法名传过来value(对象)
    ...mapMutations({ handleIncre: 'INCRE', handleDecre: 'DECRE' }),
    // 写法三:简写形式,参数需要从方法名传过来value(数组)  方法名称必须和vuex里面的方法相同
    // ...mapMutations(['INCRE', 'DECRE']),

    // ==============================================================================================

    // 写法一
    // handleIncreOdd(val) {
    //   this.$store.dispatch('increOdd', val)
    // },
    // handleIncreWait(val) {
    //   this.$store.dispatch('increWait', val)
    // },

    // 写法二:
    ...mapActions({ handleIncreOdd: 'increOdd', handleIncreWait: 'increWait' })
    // 写法三:...mapActions(["handleIncreOdd", 'handleIncreWait']) //方法名称必须和vuex里面的方法相同
  },
}
</script>

<style>
</style>

stores/index.js

// 引入 vue
import Vue from 'vue'

// 引入vuex
import Vuex from 'vuex'
Vue.use(Vuex)

// 用于存储数据
const state = {
    sum: 0,
    school: 'ans',
    subject: 'web'
}

// 用于操作数据(state)
const mutations = {
    INCRE(state, value) {
        state.sum += value
    },

    DECRE(state, value) {
        state.sum -= value
    }
}

// 用于响应组件中的动作
const actions = {

    increOdd(context, value) {
        if (context.state.sum % 2) {
            context.commit('INCRE', value)
        }
    },

    increWait(context, value) {
        setTimeout(() => {
            context.commit('INCRE', value)
        }, 1000);
    }

}

// 用于 state 中数据加工
const getters = {
    bigSum(state) {
        return state.sum * 10
    }
}

// 创建store并导出 store
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters
})

Demo2 ==> 计算小例子

main.js

import Vue from 'vue'
import App from './App'
import router from './router' 
import store from './store' 

Vue.config.productionTip = false


// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// })


new Vue({
  el: '#app',
  render:h => h(App),
  router,
  //将创建的共享数据对象,挂载在vue实例中
  //所有的组件,就可以直接从store中获取全局的数据了
  store
})

store.js

import { subset } from 'semver'
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    //state中存放的就是全局共享的数据
    state: {
        //全局count值為0
        count: 0
    },
    mutations: {
        //定义一个add函数  第一个参数永远都是一个state 代表全局对象
        //加1
        add(state) {
            state.count++
        },
        //加N
        addN(state, step) {
            state.count += step
        },
        //减1
        sub(state) {
            state.count--
        },
        //减N
        subN(state, step) {
            state.count -= step
        }

    },
    actions: {
        //异步操作  context相当于new 出来的store的实体对象
        addAsync(context) {
            setTimeout(() => {
                //修改state中的数据必须通过mutations
                context.commit('add')
            }, 2000)
        },
        //等会2秒异步加N
        addAsyncN(context, step) {
            setTimeout(() => {
                //修改state中的数据必须通过mutations
                context.commit('addN', step)
            }, 2000)
        },
        //等待2秒异步减1
        subAsync(context) {
            setTimeout(() => {
                //修改state中的数据必须通过mutations
                context.commit('sub')
            }, 2000)
        },
        //等待2秒异步减N
        subAsyncN(context, step) {
            setTimeout(() => {
                //修改state中的数据必须通过mutations
                context.commit('subN', step)
            }, 2000)
        }

    },
    getters: {
        //定义函数
        showNum(state) {
            return '当前最新数据是[' + state.count + ']'
        }
    }
})

addition.vue 加法组件

<template>
  <div>
    <!-- 加法组件 -->

    <!-- 组件访问state中数据的第一种方式 this.$store.state.全局数据名称 -->
    <h3>当前最新的count值为:{{ $store.state.count }}</h3>
    <h3>getter包装的:{{ $store.getters.showNum }}</h3>
    <button @click="btnadd">+1</button>
    <button @click="btnadd2">+3</button>
    <button @click="btnadd3">等待2秒异步+1</button>
    <button @click="btnadd4">等待2秒异步+10</button>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  methods: {
    //调用mutations中提供的一个函数
    btnadd() {
      this.$store.commit('add');
    },
    
    btnadd2() {
      this.$store.commit('addN', 3);
    },

    btnadd3() {
      //dispatch函数 专门用来触发 action
      this.$store.dispatch('addAsync');
    },

    btnadd4() {
      //dispatch函数 专门用来触发 action
      this.$store.dispatch('addAsyncN', 10);
    },
  },
};
</script>

subtraction.vue 减法组件

<template>
  <div>
    <!-- 减法组件 -->
    <h3>当前最新的count值为:{{ count }}</h3>
    <h3>getter包装的:{{ showNum }}</h3>
    <button @click="sub">-1</button>
    <button @click="subN(3)">-3</button>
    <button @click="btnSub3">等待2秒异步-1</button>
    <button @click="btnSub4">等待2秒异步-10</button>
  </div>
</template>

<script>
//组件访问state中数据的第二种方式 先导入
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex';

export default {
  data() {
    return {};
  },
  computed: {
    //...展开运算符  吧全局里面的那些数据映射为当前组件的计算属性
    //count store中全局共享数据名称   获取store中的数据
    ...mapState(['count']),
    ...mapGetters(['showNum']),
  },
  methods: {
    ...mapMutations(['sub', 'subN']), //吧全局mutations里面的sub函数映射为当前组件的methods
    ...mapActions(['subAsync', 'subAsyncN']),
    // btnSub(){
    //     this.sub();//或者直接加到@click上
    // },
    // btnSub2(){
    //     this.subN(3);//或者直接加到@click上
    // },
    btnSub3() {
      this.subAsync(); //或者直接加到@click上
    },
    btnSub4() {
      this.subAsyncN(10); //或者直接加到@click上
    },
  },
};
</script>

App.vue 跟组件

<template>
  <div>
    <my-add></my-add>
    <p>-------------------------------------------</p>
    <my-sub></my-sub>
  </div>
</template>

<script>
//导入组件
import addition from './components/addition.vue';
import subtraction from './components/subtraction.vue';

export default {
  name: 'App',
  //注册组件
  components: {
    'my-add': addition,
    'my-sub': subtraction,
  }
}
</script>

<style>
</style>

效果图如下:

测试.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容