1. 程式人生 > >vue-cli搭建的專案中使用vuex實現狀態管理

vue-cli搭建的專案中使用vuex實現狀態管理

1、安裝

使用vue-cli搭建好專案以後,安裝vuex

npm install vuex --save-dev

2、建立Vuex.Store例項

對於大型應用,需要儲存的狀態可能很多,我們就將store中的state、getters 、mutations 和 actions分割到單獨的檔案中。並且把 Vuex 相關程式碼分割到模組中。

在專案的src資料夾下建立一個名為store的資料夾,store資料夾下的檔案目錄如下所示:

src/store/index.js  檔案是組裝模組並匯出store的地方

import Vue from 'vue';
import Vuex from 'vuex';

import state from './state.js';
import getters from './getters.js';
import mutations from './mutations.js';
import actions from './actions.js';
import modules from './modules/modules.js';

Vue.use(Vuex);

const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions,
  modules
});

export default store;

3、state.js

const state = {
  count: 0,
  number: 0,
  username: 'liu',
  nickname: 'never',
  password: 123
};

export default state;

4、getters.js

const getters = {
  message: state => {
    return '使用者名稱為:' + state.username;
  },
  msg: state => {
    return `暱稱為:${state.nickname}`;
    // 等價於  return '暱稱為:' + state.nickname;
    // `${}` 是ES6中的模版字串語法
  }
};

export default getters;

5、mutations.js

const mutations = {
  increment: state => {
    state.count++;
  },
  asnyAdd: state => {
    state.number++;
  },
  changePassword: (state, payload) => {
    state.password = payload.password;
  },
  changeNickname: (state, payload) => {
    state.nickname = payload.nickname;
  }
};

export default mutations;

6、actions.js

const actions = {
  asnyAdd: context => {
    context.commit('asnyAdd');
  },
  changeNickname ({commit}, payload) {
    commit('changeNickname', payload);
  }
};

export default actions;

7、在Vue元件中使用

<template>
  <div>
    <h1>{{study}}</h1>

    <button @click="increment">同步加1</button>
    <button @click="asnyAdd">非同步加1</button>

    <button @click="changePassword({password: 123456})">同步修改密碼</button>
    <button @click="changeNickname({nickname: 'sleepwalker'})">非同步修改暱稱</button>

    <p>count:{{count}}</p>
    <p>number:{{number}}</p>
    <p>username:{{username}}</p>
    <p>nickname:{{nickname}}</p>
    <p>password:{{password}}</p>

    <p>{{message}}</p>
    <p>{{msg}}</p>
  </div>
</template>

<script>

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex';

export default {
  data () {
    return {
      study: 'vuex-study'
    };
  },
  computed: {

    ...mapState(['count', 'number', 'username', 'nickname', 'password']),

    ...mapGetters(['message', 'msg'])

  },
  methods: {

    ...mapMutations(['increment', 'changePassword']),

    ...mapActions(['asnyAdd', 'changeNickname'])

  }
};
</script>

8、modules

(1)modules.js

import moduleA from './moduleA.js';
import moduleB from './moduleB.js';

const modules = {
  moduleA,
  moduleB
};

export default modules;

(2)moduleA.js

// 預設情況下,模組內部的 action、mutation 和 getter 是註冊在全域性名稱空間的
// 模組的狀態預設註冊在全域性名稱空間,為一個物件,物件中的屬性是模組中的狀態

const moduleA = {
  state: {
    countA: 1,
    nameA: 'moduleA'
  },

  // 模組內部的 mutation 和 getter,接收的第一個引數是模組的區域性狀態物件。
  getters: {
    // 這裡的 state 物件是模組的區域性狀態
    msgA: state => {
      return `模組A的名稱為:${state.nameA}`;
    },
    // 對於模組內部的 getter,根節點狀態作為第三個引數(rootState)暴露出來
    msgTotal: (state, getters, rootState) => {
      return `根節點使用者名稱為:${rootState.username},模組A的名稱為:${state.nameA}`;
    }
  },

  // 在模組的muatations中不能使用根節點狀態,因為muatations中是同步更新狀態
  mutations: {
    addA (state) {
      state.countA++;
    }
  },

  // 對於模組內部的 action,區域性狀態通過 context.state 暴露出來,根節點狀態則為 context.rootState
  actions: {
    asnyAddA (context) {
      context.commit('addA');
      console.log('區域性狀態countA為:' + context.state.countA);
      console.log(context.rootState); // 根節點狀態是一個物件
      console.log('根節點狀態count為:' + context.rootState.count);
    }
  }
};

export default moduleA;

(3)在Vue元件中使用moduleA中的狀態

moduleA.vue

<template>
  <div>
    <h1>{{study}}</h1>

    <button @click="addA">同步加1</button>
    <button @click="asnyAddA">非同步加1</button>

    <p>countA:{{moduleA.countA}}</p>
    <p>nameA:{{moduleA.nameA}}</p>

    <p>{{msgA}}</p>
    <p>{{msgTotal}}</p>
  </div>
</template>

<script>

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex';

export default {
  data () {
    return {
      study: 'vuex-module-study'
    };
  },

  computed: {
    ...mapState(['moduleA']),
    ...mapGetters(['msgA', 'msgTotal'])
  },

  methods: {
    ...mapMutations(['addA']),
    ...mapActions(['asnyAddA'])
  },
  
  mounted () {
    console.log(this.$store.state.moduleA); // 是一個物件
    console.log('moduleA.countA:' + this.$store.state.moduleA.countA);
    console.log(this.$store.getters.msgA);
    console.log(this.$store.getters.msgTotal);
  }
};
</script>

(4)moduleB.js

const moduleB = {

  state: {
    countB: 1,
    nameB: 'moduleB'
  },

  getters: {
    msgB: state => {
      return `模組B的名稱為:${state.nameB}`;
    }
  },

  mutations: {
    addB (state) {
      state.countB++;
    }
  },

  actions: {
    asnyAddB ({ state, commit, rootState }) {
      commit('addB');
      console.log('區域性狀態countB為:' + state.countB);
      console.log('根節點狀態count為:' + rootState.count);
    }
  }
};

export default moduleB;

(5)在Vue元件中使用moduleB中的狀態

moduleB.vue

<template>
  <div>
    <h1>{{study}}</h1>

    <button @click="addB">同步加1</button>
    <button @click="asnyAddB">非同步加1</button>

    <p>countB:{{moduleB.countB}}</p>
    <p>nameB:{{moduleB.nameB}}</p>

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

<script>

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex';

export default {
  data () {
    return {
      study: 'vuex-module-study'
    };
  },

  computed: {
    ...mapState(['moduleB']),
    ...mapGetters(['msgB'])
  },

  methods: {
    ...mapMutations(['addB']),
    ...mapActions(['asnyAddB'])
  }
};
</script>