1. 程式人生 > >Vue.js狀態管理模式 Vuex

Vue.js狀態管理模式 Vuex

在這裡插入圖片描述

vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

安裝、使用 vuex

首先我們在 vue.js 2.0 開發環境中安裝 vuex :


npm install vuex --save

然後 , 在 main.js 中加入 :


import vuex from 'vuex'
Vue.use(vuex);
const store = new vuex.Store({//store物件
    state:{
        show:false,
        count:0
    }
})

再然後 , 在例項化 Vue物件時加入 store 物件 :


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

現在,你可以通過 store.state 來獲取狀態物件,以及通過 store.commit 方法觸發狀態變更:


store.commit('increment')

console.log(store.state.count) // -> 1

State

在 Vue 元件中獲得 Vuex 狀態

從 store 例項中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:


// 建立一個 Counter 元件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

mapState 輔助函式

當一個元件需要獲取多個狀態時候,將這些狀態都宣告為計算屬性會有些重複和冗餘。為了解決這個問題,我們可以使用 mapState 輔助函式幫助我們生成計算屬性:


// 在單獨構建的版本中輔助函式為 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭頭函式可使程式碼更簡練
    count: state => state.count,

    // 傳字串引數 'count' 等同於 `state => state.count`
    countAlias: 'count',

    // 為了能夠使用 `this` 獲取區域性狀態,必須使用常規函式
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

當對映的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字串陣列:


computed: mapState([
  // 對映 this.count 為 store.state.count
  'count'
])

Getter

getters 和 vue 中的 computed 類似 , 都是用來計算 state 然後生成新的資料 ( 狀態 ) 的,就像計算屬性一樣,getter 的返回值會根據它的依賴被快取起來,且只有當它的依賴值發生了改變才會被重新計算。

Getter 接受 state 作為其第一個引數:


const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

通過屬性訪問

Getter 會暴露為 store.getters 物件,你可以以屬性的形式訪問這些值:


store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]

Getter 也可以接受其他 getter 作為第二個引數:


getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}

store.getters.doneTodosCount // -> 1

元件中使用:


computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}

注意,getter 在通過屬性訪問時是作為 Vue 的響應式系統的一部分快取其中的。

通過方法訪問

通過方法訪問

你也可以通過讓 getter 返回一個函式,來實現給 getter 傳參。在你對 store 裡的陣列進行查詢時非常有用:


getters: {
  // ...
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

注意,getter 在通過方法訪問時,每次都會去進行呼叫,而不會快取結果。

mapGetters 輔助函式

mapGetters 輔助函式僅僅是將 store 中的 getter 對映到區域性計算屬性:


import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用物件展開運算子將 getter 混入 computed 物件中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

如果你想將一個 getter 屬性另取一個名字,使用物件形式:


mapGetters({
  // 把 `this.doneCount` 對映為 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})

Mutation

更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。

註冊:


const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變更狀態
      state.count++
    }
  }
})

呼叫:


store.commit('increment')

提交載荷(Payload)

你可以向 store.commit 傳入額外的引數,即 mutation 的 載荷(payload):


// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}

store.commit('increment', 10)

如果提交多個引數,必須使用物件的形式進行提交


// ...
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

store.commit('increment', {
  amount: 10
})

注:mutations裡的操作必須是同步的;

Action

Action 類似於 mutation,不同在於:

  • Action 提交的是 mutation,而不是直接變更狀態。
  • Action 可以包含任意非同步操作。

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

Action 通過 store.dispatch 方法觸發:


store.dispatch('increment')

在 action 內部執行非同步操作:


actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

物件形式傳參:


// 以載荷形式分發
store.dispatch('incrementAsync', {
  amount: 10
})

來源:https://segmentfault.com/a/1190000016229077