談一談我是怎么學(xué)習(xí)使用vuex的

好久沒(méi)有寫(xiě)文章了,感覺(jué)自己就這樣稀里糊涂的過(guò)了好久了。最近在研究小程序 本來(lái)想等小程序有所得之后再來(lái)寫(xiě)點(diǎn)什么。但是發(fā)現(xiàn)自己研究來(lái)研究去 ,感覺(jué)沒(méi)沒(méi)有什么好寫(xiě)的。但是又不想丟棄掉自己寫(xiě)作的一個(gè)習(xí)慣。剛好前段時(shí)間在重構(gòu)代碼的時(shí)候,發(fā)現(xiàn)了之前封裝代碼的時(shí)候出現(xiàn)了很多的奇怪的寫(xiě)法,和很多之前沒(méi)考慮到的漏洞,多少還是有點(diǎn)心得的,寫(xiě)下這個(gè)文章呢?和大家交流一下

一、 為什么要用vuex

首先我們談到一個(gè)技術(shù)肯定是要從以下幾個(gè)方面來(lái)進(jìn)行探究的:

  • 什么情況下要用這項(xiàng)技術(shù)
  • 這項(xiàng)技術(shù)相對(duì)于其他技術(shù)的優(yōu)勢(shì)

我這里呢?就從這兩個(gè)方面來(lái)開(kāi)始,逐次、深層次的介紹vuex。

首先現(xiàn)今幾大主流的框架:react,vue,angluar包括小程序,無(wú)以復(fù)加的都提出一個(gè)組件化的思想。這樣做的好處是:高內(nèi)聚、可重用、可互換、可組合等優(yōu)勢(shì),但同時(shí)也在開(kāi)發(fā)中帶來(lái)了許多新的問(wèn)題,其中最重大的研究課題是:組件間的通信

前端也差不多開(kāi)發(fā)了一年半的時(shí)間了,主流的幾種vue的組件間傳遞信息的方式,無(wú)非有以下幾種:
1、 通過(guò) $emitprops在父子組件中進(jìn)行數(shù)據(jù)傳遞。
2、 用eventbus(全局事件)在中進(jìn)行傳遞。
3、 利用localstorage、sessionstorage等存儲(chǔ)手段來(lái)進(jìn)行傳遞。
毫無(wú)疑問(wèn),這些個(gè)方式都能完成我們所要的需求。但是在某種程度上面或多或少都有一些問(wèn)題。例如:
1、 利用$emitprops在兄弟關(guān)系嵌套比較深的情況之下,代碼書(shū)寫(xiě)量將會(huì)大大的增加。
2、 全局事件在使用的時(shí)候可能被被多次觸發(fā)、銷(xiāo)毀時(shí)機(jī)掌握等等一系列的問(wèn)題,同時(shí)作為全局事件所有頁(yè)面都能監(jiān)聽(tīng)、掌控事件可能會(huì)存在安全性問(wèn)題等等...
3、 ...

既然前面說(shuō)了這么多其他技術(shù)的壞話,現(xiàn)在就要來(lái)介紹一下今天文章的主角了。
vuex--是一個(gè)專為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。

首先來(lái)明確幾個(gè)概念:
一、狀態(tài)管理模式


上面是一個(gè)vue簡(jiǎn)單的狀態(tài)管理應(yīng)用,其中應(yīng)該包含有:

  • state,驅(qū)動(dòng)應(yīng)用的數(shù)據(jù)源;
  • view,以聲明方式將 state 映射到視圖;
  • actions,響應(yīng)在 view 上的用戶輸入導(dǎo)致的狀態(tài)變化。

當(dāng)然上面只是一個(gè)最簡(jiǎn)單的“單向數(shù)據(jù)流”的示意圖。但是當(dāng)我們存在很多的組件嵌套的時(shí)候,可能會(huì)存在這樣幾個(gè)問(wèn)題:

  • 多個(gè)視圖依賴于同一狀態(tài)。
  • 來(lái)自不同視圖的行為需要變更同一狀態(tài)。

顯然用前面的哪幾個(gè)技術(shù)可能會(huì)將頁(yè)面的狀態(tài)變得更加復(fù)雜和代碼邏輯繁瑣,不利于代碼的維護(hù)和深層次開(kāi)發(fā)。在這種大環(huán)境下面,設(shè)計(jì)師們專門(mén)為vuex設(shè)計(jì)了一款狀態(tài)管理庫(kù),以利用 Vue.js 的細(xì)粒度數(shù)據(jù)響應(yīng)機(jī)制來(lái)進(jìn)行高效的狀態(tài)更新。



上面便是vuex的工作流程,下面我們就開(kāi)始簡(jiǎn)單的來(lái)介紹一下vuex的一些構(gòu)成。

二、 vuex的簡(jiǎn)單介紹

說(shuō)到vuex的介紹呢?我們就先從代碼的引入開(kāi)始:

npm install vuex --save
import Vue from "vue";
import Vuex from "vuex"

Vue.use(Vuex)

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

最后再main.js中:

import store from "./store"
var app=new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

看了上面的代碼,首先來(lái)解釋一下:new Vuex.Store({}) 表示創(chuàng)建一個(gè)Vuex實(shí)例,通常情況下,他需要注入到Vue實(shí)例里. Store是Vuex的一個(gè)核心方法,字面上理解為“倉(cāng)庫(kù)”的意思。Vuex Store是響應(yīng)式的,當(dāng)Vue組件從store中讀取狀態(tài)(state選項(xiàng))時(shí),若store中的狀態(tài)發(fā)生更新時(shí),他會(huì)及時(shí)的響應(yīng)給其他的組件(類似雙向數(shù)據(jù)綁定) 而且不能直接改變store的狀態(tài),改變狀態(tài)的唯一方法就是,顯式地提交更改(mutations選項(xiàng))

上面就將vuex的四個(gè)核心選項(xiàng):state mutations getters actions說(shuō)了出來(lái)。

2.1、 state:

首先是state,如何來(lái)獲取state的值呢?一般是將這個(gè)值放置在computer里面,這樣的話一旦數(shù)據(jù)發(fā)生改變的時(shí)候,就反饋到頁(yè)面上面去。代碼如下:

// state_name:klivitam
<template>
  <div>
    {{username}}
  </div>
</template>

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

state總結(jié):用來(lái)存放組件之間共享的數(shù)據(jù)。他跟組件的data選項(xiàng)類似,只不過(guò)data選項(xiàng)是用來(lái)存放組件的私有數(shù)據(jù)。

2.2、 getters:

其次是getters,來(lái)看下面一段代碼:
vuex里面的代碼

import Vue from "vue";
import Vuex from "vuex"

let state = {
  name:"klivitam"
}
let getters = {
  getName(state){
    return `我的名字是:${state.name}`;
  }
}
let mutations = {}
let actions = {}

Vue.use(Vuex)

export default new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

vue內(nèi)的代碼:

<template>
  <div>
    {{username}}
  </div>
</template>

<script>
  export default {
    data(){
      return{
        message: '我是一個(gè)菜鳥(niǎo)',
      }
    },
    computed:{
      username(){
        return this.$store.getters.getName;
      }
    }
  }
</script>

chrome頁(yè)面的效果圖:


getters總結(jié): getters主要是用來(lái)過(guò)濾和重組。這些事件最好也是能在計(jì)算屬性中完成,用于監(jiān)聽(tīng)事件變化的。

2.3、mutations:

來(lái)看下面一段代碼:
vue代碼:

<template>
  <div>
    {{username}}
    <div>
      <button @click="change">更改我的昵稱</button>
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        message: '我是一個(gè)菜鳥(niǎo)',
      }
    },
    methods:{
      change(){
        this.$store.commit("changeName","jkb...")
      }
    },
    computed: {
      username() {
        return this.$store.getters.getName;
      }
    }
  }
</script>

store代碼:

let mutations = {
  changeName(state,name){
    state.name = name;
  }
}

點(diǎn)擊后效果:


mutations總結(jié):在 Vuex store 中,實(shí)際改變 狀態(tài)(state) 的唯一方式是通過(guò) 提交(commit) 一個(gè) mutation。mutations下的函數(shù)接收state作為參數(shù),兩一個(gè)參數(shù)叫做payload(載荷),payload是用來(lái)記錄開(kāi)發(fā)者使用該函數(shù)的一些信息,比如說(shuō)提交了什么,提交的東西是用來(lái)干什么的,包含多個(gè)字段,所以載荷一般是對(duì)象(其實(shí)這個(gè)東西跟git的commit很類似)還有一點(diǎn)需要注意:mutations方法必須是同步方法!

2.4、 actions:

來(lái)看下面一段代碼:
vue的代碼:

 change(){
        this.$store.dispatch("changeName","jkb...")
      }

store的代碼:

let mutations = {
  changeName(state,name){
    state.name = name;
  }
}
let actions = {
  changeName({commit},name){
    let timer = setTimeout(()=>{
      commit("changeName",name);
      clearTimeout(timer);
    },1000)
  }
}

actions總結(jié):actions的作用其實(shí)和mutations是沒(méi)有差別的,無(wú)非就是一個(gè)同步、異步的差別罷了。而在功能上面主要有一下兩個(gè)區(qū)別:

  • actions 提交的是 mutations,而不是直接變更狀態(tài)。也就是說(shuō),actions會(huì)通過(guò)mutations,讓mutations幫他提交數(shù)據(jù)的變更。
  • actions 可以包含任意異步操作。ajax、setTimeout、setInterval不在話下。

最簡(jiǎn)單的使用,其實(shí)也就這些 但是很可能會(huì)存在很多深沉次的思考,接下來(lái) 我就趁熱打鐵,寫(xiě)一寫(xiě)vuex深沉次的思考。

三、 vuex的深層次思考

關(guān)于深層次的思考,我也做了這么久了。我其實(shí)主要的考量有兩個(gè)地方:

  • 當(dāng)一個(gè)組件需要獲取多個(gè)狀態(tài)時(shí)候,將這些狀態(tài)都聲明為計(jì)算屬性會(huì)有些重復(fù)和冗余。
  • 當(dāng)頁(yè)面的屬性過(guò)多的時(shí)候,代碼的可維護(hù)性下降。

針對(duì)上面的情況,我從這倆個(gè)切入點(diǎn) 說(shuō)說(shuō)我的想法:

1、 頁(yè)面計(jì)算屬性重復(fù)和冗余問(wèn)題:

關(guān)于頁(yè)面計(jì)算屬性重復(fù)和冗余的問(wèn)題,其實(shí)官方存在一個(gè)map函數(shù)來(lái)解決這個(gè)問(wèn)題。來(lái)看下面一段代碼。

  import {mapState,mapGetters} from "vuex"

  computed: {
      ...mapState([
        "name",
        "type"
      ]),
      ...mapGetters([
        "getName"
      ])
    }

這種做法也能達(dá)到效果。當(dāng)然也可以進(jìn)行重新命名的,例如這樣:

  ...mapState({
        name:state=>state.name,
        type:state=>state.type
      })

2、如何按功能模塊分state屬性:

當(dāng)我們項(xiàng)目開(kāi)始復(fù)雜起來(lái)的時(shí)候,我們發(fā)現(xiàn)單個(gè)的vuex文件已經(jīng)無(wú)法去滿足我們的眼球了,當(dāng)然也是能夠進(jìn)行維護(hù)的,只是維護(hù)起來(lái)的成本開(kāi)銷(xiāo)比較大。此時(shí)就需要引入一個(gè)新的概念:Module. module主要的功能是將大型的store分成一個(gè)個(gè)模塊。
來(lái)看下面一段代碼:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

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

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

這樣來(lái)獲取的時(shí)候:

 ...mapState({
        a: state => state.moduleA.a,
})

這里有一個(gè)問(wèn)題,就是在派發(fā)(dispatch)的時(shí)候,是沒(méi)有做任何的區(qū)別的,所以很可能會(huì)遇到兩個(gè)模塊的actions事件名字是一樣的。我在這里呢?看到了 一個(gè)新的解決辦法--命名空間。來(lái)看下面一段代碼:

const store = new Vuex.Store({
  modules: {
    account: {
      namespaced: true,

      // 模塊內(nèi)容(module assets)
      state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了,使用 `namespaced` 屬性不會(huì)對(duì)其產(chǎn)生影響
      getters: {
        isAdmin () { ... } // -> getters['account/isAdmin']
      },
      actions: {
        login () { ... } // -> dispatch('account/login')
      },
      mutations: {
        login () { ... } // -> commit('account/login')
      },

      // 嵌套模塊
      modules: {
        // 繼承父模塊的命名空間
        myPage: {
          state: { ... },
          getters: {
            profile () { ... } // -> getters['account/profile']
          }
        },

        // 進(jìn)一步嵌套命名空間
        posts: {
          namespaced: true,

          state: { ... },
          getters: {
            popular () { ... } // -> getters['account/posts/popular']
          }
        }
      }
    }
  }
})

當(dāng)然modules里面還有很多深層次的使用方法,這就需要你去做更深層次的研究了,例如在帶命名空間的模塊內(nèi)訪問(wèn)全局內(nèi)容、在帶命名空間的模塊注冊(cè)全局 action...等等。在實(shí)際的開(kāi)發(fā)中其實(shí)會(huì)用到很多的 這就需要去讀者朋友更深層次的進(jìn)行學(xué)習(xí)和使用了。

四、 vuex的封裝

前面說(shuō)了這么多,又到了愉快的封裝時(shí)間了。
store/index.js:

import vuex from 'vuex'
import aModule from "./a"
...modules
import vue from 'vue'

vue.use(vuex)
export default new vuex.Store({
  modules: {
    aModule
    ...modules
  }
})

store/aModule/types.js //主要用來(lái)封裝事件名

export default {
  ACTIONS_NAME: "ACTIONS_NAME"
}

store/aModule/actions.js //主要用來(lái)處理邏輯、注冊(cè)事件

import types from "./types";
export default {
  actions ({ commit }, data) {
    commit(types.ACTIONS_NAME, data)
  }
}

store/aModule/mutations.js //主要用來(lái)修改/保存狀態(tài)

import types from "./types"

export default {
  [types.ACTIONS_NAME](state, data) {
    // set state
  }
}

store/aModule/index.js

import actions from "./actions";
import mutations from "./mutations"
const state = {};
export default {
  namespaced: true,
  state:state,
  mutations:mutations,
  actions:actions,
  getters:{
  }
}

說(shuō)在最后

其實(shí)vuex真的是一個(gè)很不錯(cuò)的插件,也比較契合我們的開(kāi)發(fā)習(xí)慣。當(dāng)然很多人還是習(xí)慣用上面那幾種方式來(lái)維護(hù)代碼,但是我真的建議所有的程序員都在看看這個(gè)插件,學(xué)起來(lái)很簡(jiǎn)單 用起來(lái)也特別簡(jiǎn)單 最近在開(kāi)發(fā)小程序之余(公司需求,沒(méi)有用mpvue,用原生開(kāi)發(fā)),也去研究了一下vuex的源碼,如果有所得,還是會(huì)分享給大家。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中,您必須顯式地通過(guò)Vue.u...
    蕭玄辭閱讀 3,035評(píng)論 0 7
  • 上一章總結(jié)了 Vuex 的框架原理,這一章我們將從 Vuex 的入口文件開(kāi)始,分步驟閱讀和解析源碼。由于 Vuex...
    你的肖同學(xué)閱讀 1,884評(píng)論 3 16
  • vuex 場(chǎng)景重現(xiàn):一個(gè)用戶在注冊(cè)頁(yè)面注冊(cè)了手機(jī)號(hào)碼,跳轉(zhuǎn)到登錄頁(yè)面也想拿到這個(gè)手機(jī)號(hào)碼,你可以通過(guò)vue的組件化...
    sunny519111閱讀 8,156評(píng)論 4 111
  • Vuex 的學(xué)習(xí)記錄 資料參考網(wǎng)址Vuex中文官網(wǎng)Vuex項(xiàng)目結(jié)構(gòu)示例 -- 購(gòu)物車(chē)Vuex 通俗版教程N(yùn)uxt....
    流云012閱讀 1,536評(píng)論 0 7
  • https://github.com/Meiqia/MQChatViewControllerhttps://git...
    Alan龍馬閱讀 266評(píng)論 0 0

友情鏈接更多精彩內(nèi)容