Vuex的使用

529 阅读2分钟

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

应用场景

对于深层嵌套组件,依靠props进行父子组件的传递显得太过臃肿,而且难以维护。而vuex的出现就是为了解决数据传递的问题。Vuex作为一个全局管理仓库,可以管理所有组件的状态state,不同组件之间也可依靠Vuex来共享状态State。

Vuex不同于单纯的全局对象

1,Vuex的状态存储是响应式的。当Vue组件从store中读取状态时,若store的中的状态发生变化,那么相应的组件也会相应的得到高效更新。

2,改变store中状态的唯一途径就是显式地提交mutation。所有的state的改变都必须经过mutation事件,方便我们跟踪每一个状态的的变化。

核心概念

state

负责存储整个应用的状态数据。在vue组件中获取Vuex状态的方式如下,在计算属性中返回某个状态:

1,需要在DOM节点上获取到状态;

实现:在项目中,在组件中把存在Vuex中的“columns”取出来,并显示在该组件上

1),在computed中返回该状态。

computed: {
    columns(){
        return this.$store.state.columns;
    }
},

2),在需要用到的dom节点上进行操作。

<el-col :span="20">
    <el-checkbox-group   v-model="column">
        <el-checkbox :label="item.name" v-for="(item,index) in columns" :key="index">{{item.name}}</el-checkbox>
    </el-checkbox-group>
</el-col>

结果:每当store.state.columns变化时,都会重新计算属性,并且触发更新相关联的DOM。 2,在vue生命周期中获取到Vuex中的状态,可以直接用this.$store.state对象

eg:

this.id = this.$store.state.articleId;

mapState辅助函数

当一个组件需要获取多个状态时,vuex提供了mapState辅助函数生成计算属性。

实现:从Vuex中获取“activityLeft”和“columns”两个状态时,可以按以下两个方式获取。

1),直接获取

computed: {
  activityLeft(){
    return this.$store.state.activityLeft;
  },
  columns(){
    return this.$store.state.columns;
  }
}

2),用mapState辅助函数辅助函数获取

computed: {
    ...mapState([
       'activityLeft',
       'columns'
    ])
 },

mutation

上面说到,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

Vuex 中的mutation非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。

实现:在组件中改变Vuex状态中的acticleId状态,不可以用“this.$store.state.articleId = 1”这种方式进行修改,需要以下面的方面进行修改。

eg:

1),组件中需要用state.commit来唤醒mutation中的handler。例如在点击编辑时,获取到该item的id传递给对应的handler

 handleCurrentChange(id) {
   this.$store.commit("getArticleId",id);
 }

2),在Vuex中添加一一对应的handler

 mutations:{
   getArticleId(state,id){
     state.articleId = id;
   },  
}

注意:

1,最好在提前在你的 store 中初始化好所有所需属性。上述例子应该在state中先初始化好articleId。

2,mutation必须是同步函数。在 mutation 中混合异步调用会导致你的程序很难调试,如果需要处理异步操作,可以使用Action

Action

1,Action 提交的是 mutation,而不能直接变更状态

2,Action 可以包含任意异步操作

实现:在项目中,在Action中使用axios去获取数据,并把数据存进Vuex的状态里面。

1),在组件的methods中通过 store.dispatch 方法触发Action

handleSizeChange(val) {
  this.pageSize = val;
    let data = {
      "type":this.$store.state.navName,
      "wid":this.$store.state.websiteId,
      "pageSize":this.pageSize,
      "pageNum":this.pageNum,
      "searchTitle":this.searchTitle
     };
   this.$store.dispatch("getArticle",data);
},

2),在Vuex注册一一对应的Action

actions:{
  getArticle({commit},{type='',searchTitle='',wid,pageNum=1,pageSize=20}){
    axios.post(api.url+'articleList',{
      type:type,
      searchTitle:searchTitle,
      wid:wid,
      pageSize:pageSize,
      pageNum:pageNum
    }).then((response)=>{
      if(response.data.ret == 0){
        var data = response.data;
        var msg = data.msg;
        var total = data.total;
        commit('getArticle',{msg,total})
      }
    });
  },
}

3),通过提交 mutation 来记录状态变更

mutations:{
  getArticle(state,data){
    var res = data.msg;
    state.activityList = res;
    state.total = data.total;
  },
}

重点:store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

eg:一个 store.dispatch 在不同模块中可以触发多个 action 函数。

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

以上就是我在项目中基于vue-cli框架中使用Vuex的一些例子。最后上面提到的vuex状态附在下列store.js中。

import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';
import api from '../api/api.js';
Vue.use(Vuex);
let store = new Vuex.Store({
  state:{
    columns:[],
    articleId:'',
  },
  mutations:{
    getArticle(state,data){
      var res = data.msg;
      state.activityList = res;
      state.total = data.total;
    },
    getArticleId(state,id){
      state.articleId = id;
    },
  },
  actions:{
    getArticle({commit},{type='',searchTitle='',wid,pageNum=1,pageSize=20}){
      axios.post(api.url+'articleList',{
        type:type,
        searchTitle:searchTitle,
        wid:wid,
        pageSize:pageSize,
        pageNum:pageNum
      }).then((response)=>{
        if(response.data.ret == 0){
          var data = response.data;
          var msg = data.msg;
          var total = data.total;
          commit('getArticle',{msg,total})
        }
      });
    },
  }    
});
export default store;