1. 程式人生 > >vuex學習總結

vuex學習總結

多個 osc example 自定義屬性 ide def getter 其中 用法

什麽是Vuex?

官網定義:

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

這段話說明vuex有兩個特點:集中管理、狀態變化可以預測。 在介紹這兩個特點之前,先了解下什麽是狀態,以及為什麽要對狀態進行管理。

  • 狀態是驅動應用的數據源

    通俗的講就是組件中綁定的數據。例如:導航控件綁定的菜單數據、控制導航展開或收攏的數據等等。

  • 為什麽要狀態管理?

    既然狀態是組件需要綁定的數據,那為什麽不直接寫在組件的data方法裏呢?當這個狀態只在一個組件中使用時,當然直接在data中定義就可以。但是當多個組件都依賴同一個狀態或者都會修改同一個狀態時,處理起來就比較麻煩。

    因為在vue中,組件通過prop註冊自定義屬性。父組件通過給子組件的自定義屬性賦值將數據傳給子組件。另外子組件不能直接修改父組件的數據,它可以emit一個事件,將變更後的數據通過事件參數傳給父組件,父組件捕獲到事件後更新數據。 這樣的話對下面這些場景處理起來就很麻煩:

    1. 兩個兄弟關系(或者毫無關系)的組件都依賴於同一個狀態,A組件修改狀態後,B組件也要更新;此時A組件無法把修改後的狀態傳給B。
    2. 祖先向後代組件傳遞數據; 需要通過prop一層層的的傳遞,非常繁瑣。
  • vuex

    集中管理:vuex把組件的共享狀態抽取出來,以一個全局單例模式進行管理,在這種模式下,我們的組件樹構成了一個巨大的“視圖”,不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為。

    狀態變化可以預測:不允許組件直接修改狀態,而是在vuex內部,通過mutation來修改狀態,這樣每次狀態的變更都可以追蹤;
    技術分享圖片

Vuex的核心概念

每一個 Vuex 應用的核心就是 store(倉庫),store集中管理所有的狀態。它和單純的全局對象比有兩點不同:

  1. vuex中的狀態是響應式的,若 store 中的狀態發生變化,那麽相應的組件也會相應地得到高效更新;
  2. 組件不允許直接修改屬於store的狀態,而應執行 action 來分發 (dispatch) 事件通知 store 去改變,這樣使得我們可以方便地跟蹤每一個狀態的變化;

創建store對象的時候需要傳遞構造器選項,具體如下所示。構造器選項有:state, mutations, actions, getters, modules等,下面是這些選項的用法。

const store = new Vuex.Store({
  state: {
    products: [{"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
        {"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10},]
  },
  getters: {
    productsCount: state => {
        return state.products.length;
    }
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})
  • State

如何在組件中展示狀態? 通過在vue根實例中註冊store選項,store會註入到所有子組件中,這樣子組件能通過this.$store訪問到。
如果組件要顯示一個狀態,通常會先定義一個計算屬性,然後在計算屬性返回store中的狀態,組件綁定該計算屬性。

<template>
    <div>
        {{productsCount}}
    </div>
</template>

<script>
export default {
    computed: {
        productsCount() {
         return this.$store.state.productsCount;   
        }
    }
}
</script>

mapState輔助函數
當一個組件需要獲取多個狀態時,將這些狀態都聲明為計算屬性會有些重復和冗余,mapState函數可以幫助我們少輸入些代碼。

例如: store中有兩個狀態, name, phone

 new Vuex.Store({
  state: {
    name: ‘張紹‘,
    phone: ‘13800138000‘
  },
  ...
})

組件中通過mapState獲取這兩個狀態( ...是ES6中的擴展運算符, 具體用法可參考《ES6 ... 擴展運算符》)

<template>
    <div>
        {{name}} / {{phone}}
    </div>
</template>

<script>
import { mapState } from ‘vuex‘

export default {
    computed: {
        ...mapState([
          ‘phone‘,
          ‘name‘,
        ]),
    }
}
  • Getter
    有時候我們組件需要顯示加工處理後的狀態數據,例如store中有一個待辦任務列表的狀態數據,但是組件需要顯示已完成的待辦任務,如果每個組件都在自己的計算屬性進行過濾會重復操作,增加代碼量。這個時候可以在store中定義一個getter, 在這個getter中進行計算過濾,然後組件的計算屬性中直接返回這個getter。
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)
    }
  }
})

組件

computed: {
  doneTodosCount () {
    return this.$store.getters.doneTodosCount
  }
}
  • Mutation
    不允許組件直接修改狀態,更改狀態的唯一方法是提交mutation,然後在mutation中修改;

在vuex.store的mutations選項中定義一個mutation, mutation回調函數接收一個參數state,通過state取到狀態數據。

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

組件中提交mutation更改狀態

<template>
    <el-button @click="incrementCount">修改狀態</el-button>
</template>

<script>
export default {
    methods: {
        incrementCount() {
            this.$store.commit(‘increment‘);
        }
    }
}
</script>
  • Action
    mutation中的操作是同步的,如果我們需要在異步執行某些操作後修改狀態,則只能使用action。 Action可以包含異步操作,在Action中提交mutation來修改狀態。

定義一個Action

const store = new Vuex.Store({
  ...
  actions: {
    increment (context) {
      setTimeout(() => {
          context.commit(‘increment‘)
        }, 1000)
    }
  }
})

組件中分發Action

this.$store.dispatch(‘increment‘)
  • Module
    對於一個大型的應用,所有的狀態都集中在一個對象中,會變得非常臃腫。vuex允許我們將store分割成模塊,每個模塊擁有自己的state, mutation, action, getter,甚至是嵌套子模塊。類似下面代碼:
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

Vuex的安裝使用

  1. 首先安裝vuex
npm install vuex --save
  1. 顯式地通過Vue.use(),引入vuex
import Vuex from ‘vuex‘

Vue.use(Vuex)
  1. 實例化Vuex.Store對象
const store = new Vuex.Store({
  state: {
    ...
  },
  getters: {
    ...
  },
  mutations: {
    ...
  }
  actions: {
      ...
  }
})
  1. 將store註入到Vue實例中,這樣該 store 實例會註入到根組件下的所有子組件中,且子組件能通過 this.$store 訪問到
new Vue({
  el: ‘#app‘,
  router,
  store,
  template: ‘<App/>‘,
  components: { App },
});

註意事項:對於大型的應用,通常會把vuex相關代碼分割到模塊中,大概的項目結構如下:(官網有個購物車的例子可以參考)
技術分享圖片

參考資料

  • Vuex官方文檔
  • Vue組件
  • ES6 ... 擴展運算符

後記

此文是對官網資料的學習總結,其中夾雜了些自己對vuex的理解,如果有理解有誤的地方,歡迎大家指出。

vuex學習總結