1. 程式人生 > >從零開始的vue學習筆記(七)

從零開始的vue學習筆記(七)

前言

今天花一天時間閱讀完vuex的官方文件,簡單的做一下總結和記錄

Vuex是什麼

Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,以前的符合“單向資料流”理念的示意圖:

它包含三個部分:

  • state,驅動應用的資料來源;
  • view,以宣告方式將 state 對映到檢視;
  • actions,響應在 view 上的使用者輸入導致的狀態變化。

當我們的應用遇到多個元件共享狀態時,單向資料流的簡潔性很容易被破壞:

  • 多個檢視依賴於同一狀態。
  • 來自不同檢視的行為需要變更同一狀態。

實際上就是一個元件間通訊的問題,原來是用$ref直接引用子元件,或者多層巢狀元件,或者依賴注入provide

inject等暴力方式,在應用和元件複雜的情況下複雜度和可維護性都會成為巨大問題。

所以,vuex就誕生了,vuex的原理圖:

這個圖描述了vuex的資料傳導邏輯,綠色虛線部分為vuex外掛本身

  1. 首先,Vuex自身提供了一個store(倉庫),資料結構為樹形的,採用單例設計,裡面用key-value(value可以是string、數字、陣列、Object等)的形式包含了一個應用的各種狀態值,並提供了響應式的狀態更新,提供給vue元件Render來渲染。
  2. 傳統的Vue元件接受使用者對介面的操作後,通過分發(Dispatch)這些前端事件或者說響應給Vuex的Action,在Action
    中可以用來新增自己的業務邏輯,同時可以非同步呼叫一些其他的後端API
  3. Action通過Commit來提交對應的Mutations裡的方法,達到呼叫Mutations裡的方法的目的,這個時候可以用Devtools外掛來追蹤狀態資料在Mutations裡的方法呼叫前後的資料變化,形成快照等(Mutations裡的方法必須是同步的)
  4. Mutations裡的一些mutation(變異)方法體執行,改變應用的一些State狀態屬性,這些mutation是Vuex改變狀態的唯一途徑,直接修改State狀態值是不允許的(資料不可追蹤),從而形成了單向資料流的完整鏈路,同時狀態是可維護可追蹤響應式可複用

下面就一起來看看Vuex的各個詳細部分:

安裝

  • 直接下載(推薦)或者CDN引入
    從https://unpkg.com/vuex下載下來,然後通過js引入:

      <script src="/path/to/vue.js"></script>
      <script src="/path/to/vuex.js"></script>
  • npm/yarn

      //npm
      npm install vuex --save
      //yarn  
      yarn add vuex
  • 模組化的打包系統

    import Vue from 'vue'
    import Vuex from 'vuex'
    //前面vue基礎部分就有Vue.use()引入外掛的用法,
    //下面這句在打包系統中是必備的
    Vue.use(Vuex)

核心概念

  • State
    首先,Vuex的所有概念都只有一個api:圍繞Vuex.Store(...options) 這個構造器展開,類似Vue的概念都圍繞Vue的構造器展開一樣;State的作用就類似於Vue裡面的data,簡單的new Vuex的例子:

      // 如果在模組化構建系統中,請確保在開頭呼叫了 Vue.use(Vuex)
    
      const store = new Vuex.Store({
      state: {
          count: 0
      },
      mutations: {
          increment (state) {
          state.count++
          }
      }
      })

    這樣,在我們的Vue外掛裡就可以用computed計算屬性來獲取這些state值:

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

    為了簡化寫法(少些程式碼),官方提供了一個mapState輔助函式避免寫store.state.count這一長串,其他的輔助函式mapGettersmapActionsmapMutations都是類似的作用,API連結

例子:

  // 在單獨構建的版本中輔助函式為 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
    }
  })
}
  • Getter
    單純的用State裡的狀態值還不夠強大,所以Vuex提供了Getter來對State作進一步的複雜邏輯處理,類似於Vue裡面的computed計算屬性對data的進一步處理一樣。
    例子:

      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)
          }
      }
      })

    如果對更多的語法細節感興趣,可以閱讀官方連結

  • Mutation
    Mutaion中文解釋是變異,用來執行對State狀態改變的同步方法,可以簡單的類比Vue中的methods,只不過Vue中的methods沒有區分同步非同步方法,而Vuex中為了追蹤資料狀態,用Mutation執行同步方法,Action直觀性非同步方法,做了這種拆分,讓Devtools等工具發揮作用。
    例子:

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

    更多的語法細節參考連結

  • Action
    Action 類似於 mutation,不同在於:
    • Action 通過commit提交的是 mutation,而不是直接變更狀態。
    • Action 可以包含任意非同步操作
      例子:
      const store = new Vuex.Store({
      state: {
          count: 0
      },
      mutations: {
          increment (state) {
          state.count++
          }
      },
      actions: {
          increment (context) {
          context.commit('increment')
          }
      }
      })

    元件裡通過store.dispatch 來出發actions

      store.dispatch('increment')
    更多語法細節見連結
  • Module
    如果只靠一個大的store裡的state狀態樹來維護整個應用,當規模巨大,勢必會有問題,所以引入Module做模組化的拆分,拆成按照名稱空間的子狀態樹。每個模組擁有自己的 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 的狀態

    引入namespaced: true確保每個模組的獨立名稱空間,更多語法細節見連結

  • 其他
    其他的主題包括:
    • 專案結構
    • 外掛
    • 嚴格模式
    • 表單處理
    • 測試
    • 熱過載

這些主題不是核心問題,在需要看的時候或者自己感興趣的再來看,詳見連結