vuex的簡單介紹

1、vuex的定義

1)Vuex 是一個專門爲 Vue.js 應用程序開發的狀態管理模式,使用插件的形式引進項目中

2)集中存儲和管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化

3)每個 Vuex 應用的核心就是 store(倉庫),new Vue.store({...}),「store」基本上就是一個容器,它包含應用中大部分的狀態 (state)

 

2、vuex解決的問題

1)多個視圖依賴於同一狀態

2)來自不一樣視圖的行爲須要變動同一狀態

Vuex則是把組件的共享狀態抽取出來,以一個全局單例模式管理

同時,經過定義和隔離狀態管理中的各類概念並強制遵照必定的規則,代碼變得更結構化、易維護

以上就是vuex的思想

 

3、使用vuex的場景

開發大型單頁應用

 

4、vuex和全局對象的區別

1)Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。

2)你不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用

5、vuex中的5個核心概念

在index.js引進這5個概念的定義

import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import state from './state'
import mutations from './mutations'
import createLogger from 'vuex/dist/logger'
 
Vue.use(Vuex)
 
const debug = process.env.NODE_ENV !== 'production'
 
export default new Vuex.Store({
  actions,
  getters,
  state,
  mutations,
  strict: debug,
  plugins: debug ? [createLogger()] : []
})
而後,在main.js中引進index.js,並在全局Vue實例下注冊該store對象,這樣全部的組件均可以共享store對象裏面的state了

import store from './store'
new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})
 

 

1)state對象:(在computed中引入)Vuex 使用單一狀態樹——用一個對象就包含了所有的應用層級狀態;每一個應用將僅僅包含一個 store 實例

computed: {
  localComputed () { /* ... */ },
  // 使用對象展開運算符將此對象混入到外部對象中
  ...mapState({
    // ...
  })
}
state.js文件的內容 ----定義的states是在getters.js    mutations.js    actions.js文件調用

import {playMode} from 'common/js/config'
import {loadSearch, loadPlay, loadFavorite} from 'common/js/cache'
 
const state = {
  singer: {},
  playing: false,
  fullScreen: false,
  playlist: [],
  sequenceList: [],
  mode: playMode.sequence,
  currentIndex: -1,
  disc: {},
  topList: {},
  searchHistory: loadSearch(),
  playHistory: loadPlay(),
  favoriteList: loadFavorite()
}
 
export default state
 

2)getters對象:(能夠認爲是store的計算屬性),在組件中的computed中引入

 

getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算

Getter 接受 state 做爲其第一個參數,也能夠接受其餘 getter 做爲第二個參數

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

computed: {
  // 使用對象展開運算符將 getter 混入 computed 對象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
給getter 屬性另取一個名字,使用對象形式

mapGetters({
  // 把 `this.doneCount` 映射爲 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})
getters.js文件內容 ---輸出states

//獲取數據
export const singer = state => state.singer
 
export const playing = state => state.playing
 
export const fullScreen = state => state.fullScreen
 
export const playlist = state => state.playlist
 
export const sequenceList = state => state.sequenceList
 
export const mode = state => state.mode
 
export const currentIndex = state => state.currentIndex
 
export const currentSong = (state) => { 
  return state.playlist[state.currentIndex] || {}
}
 
export const disc = state => state.disc
 
export const topList = state => state.topList
 
export const searchHistory = state => state.searchHistory
 
export const playHistory = state => state.playHistory
 
export const favoriteList = state => state.favoriteList
在組件裏面獲取states

// 在組件裏面引進states
computed: {
  ...mapGetters([
    'currentIndex',
    'fullScreen',
    'playing'
  ])
}
 
//在組件裏面調用state
let index = this.currentIndex - 1
 

 

3)mutations對象:更改 Vuex 中 store 的狀態的惟一方法是commit mutation;

mutation相似於事件,每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler);

回調函數對狀態進行更改, state 做爲第一個參數

mutation-types.js文件內容----定義一些事件名,用常量表示

export const SET_SINGER = 'SET_SINGER'
 
export const SET_PLAYING_STATE = 'SET_PLAYING_STATE'
 
export const SET_FULL_SCREEN = 'SET_FULL_SCREEN'
 
export const SET_PLAYLIST = 'SET_PLAYLIST'
 
export const SET_SEQUENCE_LIST = 'SET_SEQUENCE_LIST'
 
export const SET_PLAY_MODE = 'SET_PLAY_MODE'
 
export const SET_CURRENT_INDEX = 'SET_CURRENT_INDEX'
 
export const SET_DISC = 'SET_DISC'
 
export const SET_TOP_LIST = 'SET_TOP_LIST'
 
export const SET_SEARCH_HISTORY = 'SET_SEARCH_HISTORY'
 
export const SET_PLAY_HISTORY = 'SET_PLAY_HISTORY'
 
export const SET_FAVORITE_LIST = 'SET_FAVORITE_LIST'
mutations.js文件內容-----提交一個state的修改

import * as types from './mutation-types'
//mutations裏面存放的是方法名
const mutations = {
  [types.SET_SINGER](state, singer) {
    //可以獲取到當前狀態樹的state,提交mutation的時候傳的參數
    state.singer = singer
  },
  [types.SET_PLAYING_STATE](state, flag) {
    state.playing = flag
  },
  [types.SET_FULL_SCREEN](state, flag) {
    state.fullScreen = flag
  },
  [types.SET_PLAYLIST](state, list) {
    state.playlist = list
  },
  [types.SET_SEQUENCE_LIST](state, list) {
    state.sequenceList = list
  },
  [types.SET_PLAY_MODE](state, mode) {
    state.mode = mode
  },
  [types.SET_CURRENT_INDEX](state, index) {
    state.currentIndex = index
  }
}
export default mutations
在組件裏面commit  mutation

methods:{
  // 引進一個mutation
  ...mapMutations({
    setFullScreen: 'SET_FULL_SCREEN'
  })
 
  // 修改了一個state,而後commit mutation
  back() {
    this.setFullScreen(false)
  }
}
不能直接調用mutation,須要使用store.commit(mutation)來調用

提交載荷:能夠向 store.commit 傳入額外的參數,即 mutation 的 載荷(payload),做爲mutation的第二個參數

 

 

對象風格的提交方式:直接使用包含 type 屬性的對象

 

store.commit({
  type: 'increment',
  amount: 10
})
mutations需遵照Vue的響應規則:

1)最好提早在 store實例化 中初始化好全部所需屬性

2)在對象上添加新的屬性的方法:

 Vue.set(obj, 'newProp', 123)
//以新對象替換老對象,使用對象展開運算符
state.obj = { ...state.obj, newProp: 123 }
使用常量替代mutation類型,一般在mutation-types中定義
mutation是同步函數:實質上任何在回調函數中進行的狀態的改變都是不可追蹤

 

在組件中提交mutation:

 

this.$store.commit('xxx') 提交 mutation
使用 mapMutations 輔助函數將組件中的 methods 映射爲 store.commit 調用(須要在根節點注入 store)
methods: {
    ...mapMutations([
      'increment', // 將 `this.increment()` 映射爲 `this.$store.commit('increment')`
 
      // `mapMutations` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射爲 `this.$store.commit('increment')`
    })
  }
4)actions對象:actions相似mutations,不一樣之處

 

action 提交的是 mutation,mutation直接變動狀態。
action 能夠包含任意異步操做
當某個動做觸發多個mutation的時候使用action

每個action 函數接受一個與 store 實例具備相同方法和屬性的對象,好比叫作context對象,所以能夠調用 context.commit 提交一個 mutation,經過 context.state 和 context.getters 來獲取 state 和 getters

使用參數結構來簡化代碼:

actions: {
  increment (context,payload) {
    commit('increment')
  }
}
實際上能夠寫成相似下面的形式,使用參數結構的方法來簡化代碼
actions: {
  increment ({ commit,state },{m,n}) {
    commit('increment')
  }
}
分發action:store.dispatch,在action內部執行異步操做

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}
Actions 支持載荷方式和對象方式進行分發

// 以載荷形式分發
store.dispatch('incrementAsync', {
  amount: 10
})
 
// 以對象形式分發
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})
在組件中分發action:

this.$store.dispatch('xxx') 分發 action
使用 mapActions 輔助函數將組件的 methods 映射爲 store.dispatch 調用(須要先在根節點注入 store)
actions.js文件內容 -----能夠同時修改多個states,而後commit 多個states

import * as types from './mutation-types'
import {playMode} from 'common/js/config'
import {shuffle} from 'common/js/util'
import {saveSearch, clearSearch, deleteSearch, savePlay, saveFavorite, deleteFavorite} from 'common/js/cache'
 
function findIndex(list, song) {
  return list.findIndex((item) => {
    return item.id === song.id
  })
}
 
export const selectPlay = function ({commit, state}, {list, index}) {
  commit(types.SET_SEQUENCE_LIST, list)
  if (state.mode === playMode.random) {
    let randomList = shuffle(list)
    commit(types.SET_PLAYLIST, randomList)
    index = findIndex(randomList, list[index])
  } else {
    commit(types.SET_PLAYLIST, list)
  }
  commit(types.SET_CURRENT_INDEX, index)
  commit(types.SET_FULL_SCREEN, true)
  commit(types.SET_PLAYING_STATE, true)
}
 
export const randomPlay = function ({commit}, {list}) {
  commit(types.SET_PLAY_MODE, playMode.random)
  commit(types.SET_SEQUENCE_LIST, list)
  let randomList = shuffle(list)
  commit(types.SET_PLAYLIST, randomList)
  commit(types.SET_CURRENT_INDEX, 0)
  commit(types.SET_FULL_SCREEN, true)
  commit(types.SET_PLAYING_STATE, true)
}
 
export const insertSong = function ({commit, state}, song) {
  let playlist = state.playlist.slice()
  let sequenceList = state.sequenceList.slice()
  let currentIndex = state.currentIndex
  // 記錄當前歌曲
  let currentSong = playlist[currentIndex]
  // 查找當前列表中是否有待插入的歌曲並返回其索引
  let fpIndex = findIndex(playlist, song)
  // 由於是插入歌曲,因此索引+1
  currentIndex++
  // 插入這首歌到當前索引位置
  playlist.splice(currentIndex, 0, song)
  // 若是已經包含了這首歌
  if (fpIndex > -1) {
    // 若是當前插入的序號大於列表中的序號
    if (currentIndex > fpIndex) {
      playlist.splice(fpIndex, 1)
      currentIndex--
    } else {
      playlist.splice(fpIndex + 1, 1)
    }
  }
 
  let currentSIndex = findIndex(sequenceList, currentSong) + 1
 
  let fsIndex = findIndex(sequenceList, song)
 
  sequenceList.splice(currentSIndex, 0, song)
 
  if (fsIndex > -1) {
    if (currentSIndex > fsIndex) {
      sequenceList.splice(fsIndex, 1)
    } else {
      sequenceList.splice(fsIndex + 1, 1)
    }
  }
 
  commit(types.SET_PLAYLIST, playlist)
  commit(types.SET_SEQUENCE_LIST, sequenceList)
  commit(types.SET_CURRENT_INDEX, currentIndex)
  commit(types.SET_FULL_SCREEN, true)
  commit(types.SET_PLAYING_STATE, true)
}
 
export const saveSearchHistory = function ({commit}, query) {
  commit(types.SET_SEARCH_HISTORY, saveSearch(query))
}
 
export const deleteSearchHistory = function ({commit}, query) {
  commit(types.SET_SEARCH_HISTORY, deleteSearch(query))
}
 
export const clearSearchHistory = function ({commit}) {
  commit(types.SET_SEARCH_HISTORY, clearSearch())
}
 
export const deleteSong = function ({commit, state}, song) {
  let playlist = state.playlist.slice()
  let sequenceList = state.sequenceList.slice()
  let currentIndex = state.currentIndex
  let pIndex = findIndex(playlist, song)
  playlist.splice(pIndex, 1)
  let sIndex = findIndex(sequenceList, song)
  sequenceList.splice(sIndex, 1)
  if (currentIndex > pIndex || currentIndex === playlist.length) {
    currentIndex--
  }
 
  commit(types.SET_PLAYLIST, playlist)
  commit(types.SET_SEQUENCE_LIST, sequenceList)
  commit(types.SET_CURRENT_INDEX, currentIndex)
 
  if (!playlist.length) {
    commit(types.SET_PLAYING_STATE, false)
  } else {
    commit(types.SET_PLAYING_STATE, true)
  }
}
 
export const deleteSongList = function ({commit}) {
  commit(types.SET_CURRENT_INDEX, -1)
  commit(types.SET_PLAYLIST, [])
  commit(types.SET_SEQUENCE_LIST, [])
  commit(types.SET_PLAYING_STATE, false)
}
 
export const savePlayHistory = function ({commit}, song) {
  commit(types.SET_PLAY_HISTORY, savePlay(song))
}
 
export const saveFavoriteList = function ({commit}, song) {
  commit(types.SET_FAVORITE_LIST, saveFavorite(song))
}
 
export const deleteFavoriteList = function ({commit}, song) {
  commit(types.SET_FAVORITE_LIST, deleteFavorite(song))
}
在組件裏面調用 

methods:{
  //引進actions
  ...mapActions([
    'savePlayHistory'
  ])
 
  //修改多個states
  ready() {
    this.savePlayHistory(this.currentSong)
  }
}
 

import { mapActions } from 'vuex'
 
export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 將 `this.increment()` 映射爲 `this.$store.dispatch('increment')`
 
      // `mapActions` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射爲 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 將 `this.add()` 映射爲 `this.$store.dispatch('increment')`
    })
  }
}
5)Module:使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。Vuex 容許咱們將 store 分割成模塊(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 的狀態
 

總結:在使用vuex的時候,若是使用模塊化的思想來編程的話,那麼一般狀況下就須要定義6個js文件,分別是

 

index.js    state.js    getters.js    mutation-types.js    mutation.js   actions.js
1、index.js:在這裏面去引入其餘5個JS文件,而後export 一個Vuex.store({})的實例對象,而後再main.js文件裏面import該js文件,在Vue實例裏面添加store選項,即在根節點下注冊該store對象

//index.js文件裏面的內容
//store文件夾下,編寫vuex的相關代碼
//index.js是vuex的入口文件
//vuex中的state只能經過commit修改,不能直接修改
import Vue from 'vue'
import Vuex from 'vuex'
//起別名是爲了像調用對象的方法同樣,調用模塊裏面定義的方法
import * as actions from './actions'
import * as getters from './getters'
import state from './state'
import mutations from './mutations'
//使用vuex提供的一些插件
//經過mutation方式修改state的時候,他會在console中輸出日誌
import createLogger from 'vuex/dist/logger'
//註冊插件Vuex
Vue.use(Vuex)
//npm run dev則process.env.NODE_EN=develop
//npm run builde則process.env.NODE_EN=production
//有性能損耗,因此在開發環境中使用
const debug = process.env.NODE_ENV !== 'production'
//輸出一個實例化的vuex對象
export default new Vuex.Store({
  actions,
  getters,
  state,
  mutations,
  strict: debug,
  plugins: debug ? [createLogger()] : []
})
2、state.js:在這裏面定義一些組件之間的公用狀態變量對象,而後export state對象

 

//全部的狀態都放在這個文件夾下管理
//也就是存放數據的對象
//這裏要管理的是singer
//playMode對象裏面定義了一些常量
import {playMode} from '../common/js/config'
 
const state = {
  singer: {},
  //播放的狀態
  playing: false,
  //歌單展開控制
  fullScreen: false,
  //播放的是一個列表
  playlist: [],
  //播放的歌單是一個有順序的列表
  sequenceList: [],
  //設置播放模式,順序播放,隨機播放
  mode: playMode.sequence,
  //當前播放的一個索引
  currentIndex: -1
}
export default state
3、getters.js:在這裏面定義一些常量變量,它的值是函數的返回值,用於獲取state.js中的對象的值;或者是當作store對象的計算屬性,對state.js的屬性對象進行計算,獲得一些計算結果的變量,export多個常量

 

//獲取states裏面的屬性,會作一些映射
//或者做爲計算屬性,根據states中的屬性,計算獲得另一些屬性
//代理計算屬性,在組件中在computed中能夠經過...mapGetters([])引入
//或mapGetters({}),給函數取別名
//getter的第一個參數爲state,第二個可選是getter
export const singer = state => state.singer
export const playing = state => state.playing
export const fullScreen = state => state.fullScreen
export const playlist = state => state.playlist
export const sequenceList = state => state.sequenceList
export const mode = state => state.mode
export const currentIndex = state => state.currentIndex
export const currentSong = state => {
  return state.playlist[state.currentIndex] || {}
}
4、mutation-types.js:在這裏面定義一些操做mutation的字符串常量變量名,這裏是定義一些動做名,因此名字通常是set  或者是update,而後再結合state.js中定義的變量對象,export多個常量

 

//存儲mutation的一些相關的名字,也就是一些字符串常量
//即便用常量替代mutation類型
//mutations裏面定義一些方法,這裏也就是定義mutations裏面方法的名字
// 一些動做,因此用set,update
export const SET_SINGER = 'SET_SINGER'
export const SET_PLAYING_STATE = 'SET_PLAYING_STATE'
export const SET_FULL_SCREEN = 'SET_FULL_SCREEN'
export const SET_PLAYLIST = 'SET_PLAYLIST'
export const SET_SEQUENCE_LIST = 'SET_SEQUENCE_LIST'
export const SET_PLAY_MODE = 'SET_PLAY_MODE'
export const SET_CURRENT_INDEX = 'SET_CURRENT_INDEX'
5、mutations.js:在這裏面定義一些修改state.js中變量對象的值的方法,這些方法都放在一個常量mutations對象裏面,而後export mutations

 

//輸出一個mutations對象,
//每個mutation的第一個參數state,第二個參數是payload
//用於改變state中的屬性的狀態
//這些操做都是同步操做
//在組件的methods中經過...mapMutations([])或者...mapMutations({})--用於改別名
import * as types from './mutation-types'
//mutations裏面存放的是方法名
const mutations = {
  [types.SET_SINGER](state, singer) {
    //可以獲取到當前狀態樹的state,提交mutation的時候傳的參數
    state.singer = singer
  },
  [types.SET_PLAYING_STATE](state, flag) {
    state.playing = flag
  },
  [types.SET_FULL_SCREEN](state, flag) {
    state.fullScreen = flag
  },
  [types.SET_PLAYLIST](state, list) {
    state.playlist = list
  },
  [types.SET_SEQUENCE_LIST](state, list) {
    state.sequenceList = list
  },
  [types.SET_PLAY_MODE](state, mode) {
    state.mode = mode
  },
  [types.SET_CURRENT_INDEX](state, index) {
    state.currentIndex = index
  }
}
export default mutations
6、actions.js:在這裏面定義一些常量方法,每一個常量方法用於提交多個mutation,而後輸出多個常量方法名

 

//當一個動做會觸發多個mutation則在actions裏面定義一個方法,從而觸發這些mutation
import * as types from './mutation-types'
import {playMode} from '../common/js/config'
import {shuffle} from '../common/js/util'
function findIndex(list, song) {
  return list.findIndex((item) => {
    return item.id === song.id
  })
}
export const selectPlay = function ({commit, state}, {list, index}) {
  commit(types.SET_SEQUENCE_LIST, list)
  if (state.mode === playMode.random) {
    let randomList = shuffle(list)
    commit(types.SET_PLAYLIST, randomList)
    //將在順序列表中播放的歌,在隨機播放列表中的index
    //確保點擊「隨機播放按鈕」的時候仍是當前這首歌
    index = findIndex(randomList, list[index])
  } else {
    commit(types.SET_PLAYLIST, list)
  }
  commit(types.SET_CURRENT_INDEX, index)
  commit(types.SET_FULL_SCREEN, true)
  commit(types.SET_PLAYING_STATE, true)
}
//定義一個隨機播放的action
export const randomPlay = function ({commit}, {list}) {
  commit(types.SET_PLAY_MODE, playMode.random)
  commit(types.SET_SEQUENCE_LIST, list)
  let randomList = shuffle(list)
  commit(types.SET_PLAYLIST, randomList)
  commit(types.SET_CURRENT_INDEX, 0)
  commit(types.SET_FULL_SCREEN, true)
  commit(types.SET_PLAYING_STATE, true)

--------------------- 
做者:tangxiujiang 
來源:CSDN 
原文:https://blog.csdn.net/tangxiujiang/article/details/80645416 
版權聲明:本文爲博主原創文章,轉載請附上博文連接!
相關文章
相關標籤/搜索