vue 項目實戰 (vue全家桶之--- vuex)


老規矩先安裝

npm install vuex --save

在看下面內容之前 你應該大概的看了一邊vuex官方的文檔對vuex有個大概對了解

首先

vuex 是什么?

vuex 是屬於vue中的什么,它在項目中扮演着一個什么樣的角色,起到什么作用,在項目中我是否要用到vuex。

官方文檔對vuex的解讀是:Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。

如果你是在開發一個大型的應用程序,組件與組件之間,兄弟組件之間,或者說多層嵌套組件之間,你是無法傳遞數據的。子父組件之間,也只是說通過事件保持數據的一致性,也是很繁瑣的,會變得很不好管理。而vuex就是為了解決這樣的問題,把組件的共享狀態抽取出來,以一個全局單例模式管理。組件樹構成了一個巨大的“視圖”,不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為,而且代碼將會變得更結構化且易維護。

新建一個最簡單的store

store.js

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0,
    me: {
      name: 'huangenai',
      age: 22,
      sex: '女'
    },
      list: [{name: 'hea', age: 22}, {name: 'cpq', age: 23}]
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

main.js

import store from './store.js'

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

State

驅動應用的數據源,組件之間共享的狀態。

上面代碼中的 count 就是一個共享的數據,me 也是一個共享的數據對象。

在組件中獲得state 中的count

this.$store.state.count

newvue.vue

<template>
    <div>
        new vue page
        <p>{{count}}</p>
    </div>
</template>

<script>
export default {
  name: 'newvue',
  data () {
    return {
    }
  },
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}
</script>

<style scoped>
</style>

為什么要寫在computed 里面呢,而不是寫在data里面,因為當state.count 變化的時候, 都會重新求取計算屬性,並且觸發更新相關聯的 DOM,如果你不理解可以先去看看computed

當一個組件要引用到多個狀態的時候 ,一個個寫是不是很累。不用擔心,我們有mapState 輔助函數幫助我們生成計算屬性。

在組件中引用

import { mapState } from 'vuex'
<template>
    <div>
        <p>{{count}}</p>
        <p>{{countPlusLocalState}}</p>
        <p>sex: {{sex}}</p>
        <p>age: {{myAge}}</p>
        <p>name: {{name}}</p>
    </div>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'newvue',
  data () {
    return {
      localCount: 1
    }
  },
  computed: {
    ...mapState({
      // 箭頭函數可使代碼更簡練
      sex: state => state.me.sex,
      myAge: state => state.me.age,
      name: state => state.me.name,
      // 傳字符串參數 'age' 等同於 `state => state.age`
      count: 'count',
      // 為了能夠使用 `this` 獲取局部狀態,必須使用常規函數
      countPlusLocalState (state) {
        return state.count + this.localCount
      }
    })
  }
}
</script>

<style scoped>
</style>

假設computed 里面還有別的數據,因為mapstate返回來的是一個對象所以我們這樣寫可以將數據混入

computed: { localComputed () { /* ... */ }, // 使用對象展開運算符將此對象混入到外部對象中 ...mapState({ // ... }) }

Mutation

你說你想修改state的值,this.$store.state.count = 1 這樣可不可以 no no no....  所以就有了Mutation。

切記Mutation 必須是同步函數!!!

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

在上面代碼我們新建一個store里面下的 有一個increment,就可以實現修改state里面的count

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count ++
    }
  }
})

那么如何調用increment呢??

調用 this.$store.commit(type)  類型叫increment 的 mutation。

this.$store.commit('increment')

我們還可以傳入參數

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

store.commit('increment', 10)

傳入一個對象

mutations: { increment (state, data) { state.count += data.count } }
store.commit('increment', { count: 10 })

mutations可以修改store中的狀態,但是並不是說隨隨便便修改的,比如說🥚狀態是對象的時候,你突然重新賦值過去一個新對象,原來的屬性沒了,真怎么行。

Vuex 的 store 中的狀態是響應式的,那么當我們變更狀態時,監視狀態的 Vue 組件也會自動更新。

比如 上面代碼的 state 內有個對象me 我可以新增刪除里面的屬性嗎,怎么操作呢。

最好就是一開始就定義好所有的屬性。

如果你非要新增屬性,也提供了方法。

1.     Vue.set(me, 'height','156cm')

2.    state.me = { ...state.me, height: '156cm' }

store.js

...
mutations: {
    increment (state) {
      state.count++
    },
    setWeight (state) {
      Vue.set(state.me, 'weight', '45kg')
    },
    setHeight (state) {
      state.me = { ...state.me, height: '156cm' }
    }
 }

newvue.vue 中調用

...  
methods: { setWeight () { this.$store.commit('setWeight') alert(JSON.stringify(this.$store.state.me)) }, setHeight () { this.$store.commit('setHeight') alert(JSON.stringify(this.$store.state.me)) } }

當mutations中的類型多了起來,我們在組件中要commit 某一個類型 還要去找 再復制過來 是不是很不好管理。

所以我們可以使用常量替代 mutation 事件類型,新建一個

mutation-types.js

export const SET_WEIGHT = 'SET_WEIGHT'
export const SET_HEIGHT = 'SET_HEIGHT'

store.js

import * as types from './metations-types'
  ...
  mutations: {
    increment (state) {
      state.count++
    },
    [types.SET_WEIGHT] (state) {
      Vue.set(state.me, 'weight', '45kg')
    },
    [types.SET_HEIGHT] (state) {
      state.me = { ...state.me, height: '156cm' }
    }
  }

newvue.vue

....
  methods: {
    setWeight () {
      this.$store.commit(types.SET_WEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    },
    setHeight () {
      this.$store.commit(types.SET_HEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    }
  }

 

state中有mapState, Mutations中也有mapMutations

使用 mapMutations 輔助函數將組件中的 methods 映射為 this.$store.commit 調用

newvue.vue

先引用

import { mapMutations } from 'vuex'
...
    setWeight () {
      this.$store.commit(types.SET_WEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    },
    setHeight () {
      this.$store.commit(types.SET_HEIGHT)
      alert(JSON.stringify(this.$store.state.me))
    },
    ...mapMutations([
      'increment'
      // 將 `this.increment()` 映射為 this.$store.commit('increment')`
    ])
  }

 getter

getter 又是什么 ,在store中。什么時候用到他。

上述我們可以用 this.$store.state.count 能拿到 store的state ,而getter 則是拿store中的計算屬性。

比如store 中的state 中的list 

在項目中我們有多個組件需要通過過濾拿到list中 age 大於等於22的對象,如果沒有getter 我們需要在每個組件中都要定義一個函數過濾好在返回值,或者抽出來一個公共的方法哪個組件需要的時候就導入這個方法,再進行調用,也是很麻煩的一件事。

在這里我們可以用到store 里的getter,並通過屬性訪問獲得過濾后的數據

store.js

export default new Vuex.Store({
  state: {
    ...
    list: [{name: 'hea', age: 22}, {name: 'cpq', age: 23}]
  },
  mutations: {
   ...
  },
  getters: {
    ageFilter: state => {
      return state.list.filter(item => item.age>=23)
    }
  }
})

newvue.vue

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

在getter中,Getter 也可以接受其他 getter 作為第二個參數。

例子

... 
getters: {
    ageFilter: state => {
      return state.list.filter(item => item.age >= 23)
    },
    listCount (state,getters){
        return getters.ageFilter.length
    }
}

newvue.vue中調用

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

通過方法訪問,讓getter返回一個函數,我們可以傳值過去

store.js

...
getters: {
    ....
    getName: (state) => (name) => {
      return state.list.find(item => item.name === name)
    }
  }

newvue.vue

....
computed: {
.... listbyName () { return this.$store.getters.getName('cpq') } }

getter 有mapGetters 輔助函數,將 store 中的 getter 映射到局部計算屬性

newvue.vue

import { mapGetters } from 'vuex'
  computed: {
   ....
    // listCount () {
    //   return this.$store.getters.listCount
    // },
    ...mapGetters([
      'listCount'
    ])
  }

在組件中,什么時候通過getter拿到store 狀態,什么時候 直接拿state 想必都清楚了。

Action

其實跟上述的mutation很相似。

但是他不是直接修改state,在上面mutation說過,必須是同步函數。而Action則可以包含任意異步函數,action 是通過提交 mutation,而修改state。

store.js

export default new Vuex.Store({
  state: {
    ...
  },
  mutations: {
    ...
  },
  getters: {
    ...
  },
  actions: {
    setWeight ({commit}) {
      commit(types.SET_WEIGHT)
    }
  }

Action 通過 this.$store.dispatch 方法觸發

newvue.vue

...  
methods: {
    ...
    setWeight () {
      this.$store.dispatch('setWeight')
    }
}

同樣action 也支持傳參數

action.js

export default new Vuex.Store({
  state: {
    count: 0,
    ...
  },
  mutations: {
    increment (state,count) {
      state.count = count
    },
    ...
  },
  getters: {
    ...
  },
  actions: {
    ...
    setCount ({commit},data) {
      commit('increment',data.count)
    }
  }
})

newvue.vue

methods: {
    ...
    setCount () {
      this.$store.dispatch('setCount', {count: 123})
} }

為什么要action 直接用mutation豈不更方便,為什么要通過action,又多了一步

因為mutation只是同步函數啊,在很多情況下我們要執行異步操作的。

action可以包含異步函數。

我們假設一個登錄的功能,在action中支持異步函數,在mutation只能是同步函數,所以要用到action

import api from '../api'

... 
actions: {
  login ({commit}, payload) => {
  return new Promise((resolve, reject) => {
    api.login(payload, userToken => {
      if (userToken && userToken.accessToken) {
        commit(types.LOGIN, userToken)
        resolve(userToken)
      } else {
        reject()
      }
    })
  })
}

調用

this.$store.dispatch('login', {username, password}).then(
  (res) => {
             
}).catch()

同樣action也有輔助函數 mapActions

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')`
  }
}

你還可以action中相互調用

actions: {
    ...
    setCountA ({commit},count) {
      commit('increment', count)
    },
    setCountB ({commit},data) {
      dispatch('setCountA',data.count)
    }
}

  

此隨筆乃本人學習工作記錄,如有疑問歡迎在下面評論,轉載請標明出處。

如果對您有幫助請動動鼠標右下方給我來個贊,您的支持是我最大的動力。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM