Vuex

142 阅读2分钟

vuex

注意: 子孙组件之间建议用 provide/inject(后续更新),不要滥用Vuex;

什么时候用vuex?

  1. 当一个组件需要多次派发事件
  2. 跨组件共享数据、跨页面共享数据

vuex使用

在安装vuex之后,在项目中会多出一个store目录,目录下有一个index.js文件

Vue.use(Vuex);

const store = new Vuex.Store({
  // 在开发环境开启严格模式 这样修改数据 就必须通过 mutation 来处理
  strict: products.env.NODE_ENV !== "production",
  //状态 相当于data里面的数据
  state: {
    name: "卜卜",
    age: 21,
  },
  //用来处理状态
  mutations: {},
  //用于异步处理
  actions: {},
  //用来挂载模块
  modules: {
    app,
    settings,
    user,
  },
  // getters,
});

export default store;

mian.js将store挂载到Vue中,便于全局使用


Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

1.state

state里面的数据类似于data里面的初始值

Vue.use(Vuex);

const store = new Vuex.Store({
  // 在开发环境开启严格模式 这样修改数据 就必须通过 mutation 来处理
  strict: products.env.NODE_ENV !== "production",
  //状态 相当于data里面的数据
  state: {
    name: "卜卜",
    age: 21,
  },
  mutations: {},
  actions: {},
  modules: {
    app,
    settings,
    user,
  },

});
export default store;

2.组件获取state里数据的方法

通过 this.$store.state.[属性] (this可以省略)
<template>
  <div class="dashboard-container">
    <div class="dashboard-form">{{ this.$store.state.name }}</div>
  </div>
</template>
通过 mapState
<template>
  <div class="dashboard-container">
    <div>{{ name }}</div>
    <div>{{ age }}</div>
  </div>
</template>

<script>
import {  mapState } from "vuex";
export default {
  name: "Dashboard",
  data() {
    return {};
  },
  computed: {
    ...mapState(["name", "age"]),
  },

};
</script>
mapState还可以在对象中给状态起别名,在 mapState 方法里传递一个对象而不是数组
 <template>
  <div class="dashboard-container">
    <div >{{ name1 }}</div>
    <div>{{ name2 }}</div>
  </div>
</template>

<script>
import {  mapState } from "vuex";
export default {
  name: "Dashboard",
  data() {
    return {};
  },
  computed: {
    ...mapState({ name1: "name", name2: "age" }),
  },
};
</script>

2.mutations

Store 中的状态不能直接对其进行操作,我们得使用 Mutation 来对 Store 中的状态进行修改

在组件中使用mutation的方法

1、使用this.$store.commit()

里面的第一个参数是state - Store 中的状态(必须传递)

后面多个是传入的参数

<template>
  <div class="dashboard-container">
    <div>{{ name }}</div>
    <div>{{ age }}</div>
    <button @click="btnChangeAge">切换</button>
  </div>
</template>

<script>
import { mapGetters, mapState } from "vuex";
export default {
  data() {
    return {};
  },
  computed: {
    ...mapState(["name", "age"]),
  },
  created() {},
  methods: {
    btnChangeAge() {
     //例如这里调用
      this.$store.commit("changeAge", "18");
    },
  },
};
</script>

2、 使用 mapMutations 例如切换年龄为55

<template>
  <div>
    <p>{{ this.$store.state.age }}</p>
    <button @click="changeAge(55)">点击切换年纪</button>
  </div>
</template>

<script>
import { mapMutations} from "vuex";
export default {
  data() {
    return {};
  },
  computed: {},
  methods: {
    ...mapMutations(["changeAge"]),
  },
};
</script>

3、actions

action用来处理异步任务,通过action触发mutations间接改变状态,不能直接通过mutations直接改变异步状态

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

actions中调用方法的参数,第一个是上下文默认传递的参数,第二个是自己传递的参数

const store = new Vuex.Store({
  state: {
    name: "卜卜",
    age: 21
  },
  mutations: {
    changeAge(state, ageValue) {
      state.age = ageValue;
    }
  },
  //用于异步处理
  actions: {
      //使用setTimeout模拟异步
    changeAgeSet(content, ageValue) {
      setTimeout(() => {
        //调用mutations中的方法
        content.commit("changeAge", ageValue);
      }, 3000);
    }
  },
  //用来挂载模块
  modules: {}
});
在组件中使用actions的方法

1、使用this.$store.dispatch(mutations中的方法名,传入的参数)

<template>
  <div>
    <p>{{ this.$store.state.age }}</p>
    <button @click="changeAgeItem(66)">actions切换年纪</button>
  </div>
</template>

<script>
import { mapMutations, mapState } from "vuex";
export default {
  data() {
    return {};
  },
  computed: {
    ...mapState(["name", "age"]),
  },
  methods: {
    changeAgeItem(ageValue) {
        //调用actions中的方法
      this.$store.dispatch("changeAgeSet", ageValue);
    },
  },
};
</script>

2、使用mapActions 例如改变年龄为66

<template>
  <div>
    <p>{{ this.$store.state.age }}</p>
    <button @click="changeAgeSet(66)">actions切换年纪</button>
  </div>
</template>

<script>
//这里注意引入mapActions
import { mapActions, mapMutations, mapState } from "vuex";

export default {
  data() {
    return {};
  },
  computed: {
    ...mapState(["name", "age"]),
  },
  methods: {
    //通过mapActions调用actions中的方法
    ...mapActions(["changeAgeSet"]),
  },
};
</script>

4、getters

store 中定义“getter”(可以认为是 store 的计算属性)

const store = new Vuex.Store({
  state: {
    name: "卜卜",
    age: 21
  },
  mutations: {
    changeAge(state, ageValue) {
      state.age = ageValue;
    }
  },
  //用于异步处理
  actions: {
    //使用setTimeout模拟异步
    changeAgeSet(content, ageValue) {
      setTimeout(() => {
        //调用mutations中的方法
        content.commit("changeAge", ageValue);
      }, 3000);
    }
  },
  //用来挂载模块
  modules: {},
  getters: {
    descriptAge(state) {
      return `my age is ${state.age}`;
    }
  }
});
调用getter的方法

1、this.$store.getters.方法名

  <div>
    <button @click="changeAgeSet(66)">actions切换年纪</button>
    <p>{{ this.$store.getters.descriptAge }}</p>
  </div>

2、mapGetters mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

<template>
  <div>
    <p>{{ descriptAge }}</p>
  </div>
</template>

<script>
import {  mapGetters } from "vuex";

export default {
  data() {
    return {};
  },
  computed: {
   //使用mapGetters
    ...mapGetters(["descriptAge"]),
  },

};

如果你想将一个 getter 属性另取一个名字,使用对象形式:

  computed: {
   //使用对象形式
    ...mapGetters({ newAge: "descriptAge" }),
  },

5、Modules

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

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

module的使用

1、在vuex文件夹下创建一个modules文件夹在modules底下新增example.js文件,在example.js里面写入 state、mutations、actions

const state = {
  age: 100
};
const mutations = {
  changeAge(state, ageValue) {
    state.age = ageValue;
  }
};

//导出
export default {
  state,
  mutations
};

2、在vuex/index.js中的 modules 进行挂载这个模块

import Vue from "vue";
import Vuex from "vuex";
//引入example.js
import example from "./modules/example";

Vue.use(Vuex);

const store = new Vuex.Store({
  //用来挂载模块
  modules: {
    example
  },
})
export default store;

3、在组件中的使用

1、通过this.$store.state[在module中挂载的模块名][挂载的模块里的属性]

<template>
  <div>
    <p>{{ this.$store.state.example.age }}</p>
  </div>
</template>

2、也可以通过mapXXX的形式进行映射

先在导出里添加命名空间namespaced: true

const state = {
  age: 100
};
const mutations = {
  changeAge(state, ageValue) {
    state.age = ageValue;
  }
};
export default {
  //添加命名空间
  namespaced: true,
  state,
  mutations
};

在组件中使用:

<template>
  <div>
    <p>{{ age }}</p>
  </div>
</template>

<script>
import { mapActions, mapGetters, mapMutations, mapState } from "vuex";

export default {
  data() {
    return {};
  },
  computed: {
    //在组件中使用
    ...mapState("example", ["age"]),
  },
 
};
</script>