vue學習之vuex基礎詳解及源碼解讀(一)

概念

Vuex是一個專爲Vue.js應用程序開發的狀態管理模式。當項目比較龐大的時候,每一個組件的狀態不少,爲了方便管理,須要把組件中的狀態抽取出來,放入Vuex中進行統一管理。javascript

每個 Vuex 應用的核心就是store(倉庫)。"store"基本上就是一個容器,它包含着你的應用中大部分的狀態(state)。Vuex 和單純的全局對象有如下兩點不一樣:vue

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

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

簡單應用

構建vue工程
vue init webpack vuexStudy
構建後目錄結構
圖片描述
其中:
index.jswebpack

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

//若是在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex)
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    //存放組件之間共享的數據
    //在組件經過this.$store.state.count獲取
    count: 0
  },
  mutations: {
    //顯式的更改state裏的數據,不能用於處理異步事件
    //組件中經過this.$store.commit('incrementByStep');調用
    incrementByStep(state) {
      state.count++;
    }
  },
  getters:{
    //如vue中的計算屬性同樣,基於state數據的二次包裝,經常使用於數據的篩選和多個數據的相關性計算
  },
  actions:{
    //相似於mutation,用於提交mutation來改變狀態,而不直接變動狀態,能夠包含任意異步操做
  }
});

new Vuex.Store({}) 表示建立一個Vuex實例,一般狀況下,他須要注入到Vue實例裏。 Store是Vuex的一個核心方法,字面上理解爲「倉庫」的意思。Vuex Store是響應式的,當Vue組件從store中讀取狀態(state選項)時,若store中的狀態發生更新時,他會及時的響應給其餘的組件並且不能直接改變store的狀態,改變狀態的惟一方法是顯式地提交更改。git

main.js引入vuexgithub

import Vue from 'vue'
import App from './App'
//vuex文件
import store from './store'

Vue.config.productionTip = false;

/* eslint-disable no-new */
new Vue({
  el: '#app',
  //引入
  store,
  components: { App },
  template: '<App/>'
})

APP.vue引用了counter這個組件web

<div id="app">
    <!--<img src="./assets/logo.png">-->
    <!--<HelloWorld/>-->
    <counter/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld'
import counter from './components/counter'

export default {
  name: 'App',
  components: {
    //HelloWorld
    counter
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

counter.vue定義counter組件vuex

<template>
    <div id="counterContent">
      <div>{{ count }}</div>
      <button v-on:click="addCount">請點擊</button>
    </div>
</template>

<script>
    export default {
      name: "counter",
      computed: {
        count () {
          return this.$store.state.count
        }
      },
      methods:{
          addCount(){
            debugger;
            this.$store.commit('incrementByStep');
          }
      }
    }
</script>

<style scoped>
  #counterContent{
    background-color: blue;
    width:200px;
    height:50px;
  }
</style>

經過npm run dev啓動項目,最終的結果如圖:
圖片描述npm

源碼解讀

node添加Vuex依賴下載的vuex文件(node_modules目錄下)以下:
圖片描述
其中vuex.common.js在預編譯調試時,CommonJS規範的格式,可使用require("")引用的NODEJS格式。
vuex.esm.js在預編譯調試時, EcmaScript Module(ES MODULE),支持import from 最新標準的。
vuex.js直接用在<script>標籤中的,完整版本,直接就能夠經過script引用。
而vuex的源碼託管在https://github.com/vuejs/vuex,這裏研究git上的源碼。

入口

Vuex 源碼的入口是 src/index.js。

import { Store, install } from './store'
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers'

export default {
  Store,
  install,
  version: '__VERSION__',
  mapState,
  mapMutations,
  mapGetters,
  mapActions,
  createNamespacedHelpers
}

這是Vuex對外暴露的API。其中, Store是Vuex提供的狀態存儲類,一般咱們使用Vuex就是經過建立 Store的實例。接着是install方法,這個方法一般是咱們編寫第三方Vue插件的時候使用。

install

install是在store.js內暴露的方法
當Vue經過npm安裝到項目中的時候,咱們在代碼中引入第三方Vue插件須要添加下列代碼

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

//若是在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex)
Vue.use(Vuex);

執行Vue.use(Vuex)的時候,其實就是調用了install的方法並傳入Vue的引用。
Vue.use

Vue.use = function (plugin) {
    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    var args = toArray(arguments, 1);
    args.unshift(this);
    if (typeof plugin.install === 'function') {
      //調用vuex的install
      plugin.install.apply(plugin, args);
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args);
    }
    installedPlugins.push(plugin);
    return this
  };
}

install

//判斷Vue是否已存在,保證install方法只執行一次
  if (Vue && _Vue === Vue) {
    if (process.env.NODE_ENV !== 'production') {
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
      )
    }
    return
  }
  //賦值給Vue變量,index.js文件的其它地方使用Vue這個變量
  Vue = _Vue
  //調用了 applyMixin 方法,給 Vue 的實例注入一個 $store 的屬性
  applyMixin(Vue)
}

plugin參數:
圖片描述
args參數:
圖片描述

var applyMixin = function (Vue) {
  //獲取版本信息,這裏是2
  var version = Number(Vue.version.split('.')[0]);

  if (version >= 2) {
    //調用vuexInit
    Vue.mixin({ beforeCreate: vuexInit });
  } else {
    var _init = Vue.prototype._init;
    Vue.prototype._init = function (options) {
      if ( options === void 0 ) options = {};

      options.init = options.init
        ? [vuexInit].concat(options.init)
        : vuexInit;
      _init.call(this, options);
    };
  }
  //給Vue實例注入$store 的屬性,能夠經過this.$store.xxx訪問
  function vuexInit () {
    var options = this.$options;
    // store injection
    if (options.store) {
      this.$store = typeof options.store === 'function'
        ? options.store()
        : options.store;
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store;
    }
  }
};
相關文章
相關標籤/搜索