国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

瞎說vuex

OBKoro1 / 821人閱讀

摘要:本來說好寫完組件通信后就會寫相關(guān)的東西,現(xiàn)在快過去兩個(gè)多月了,主要是由于自己工作的原因,后面會保證更新速度的。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。改變中的狀態(tài)的唯一途徑就是顯式地提交。

本來說好寫完組件通信后就會寫vuex相關(guān)的東西,現(xiàn)在快過去兩個(gè)多月了,主要是由于自己工作的原因,后面會保證更新速度的。不廢話了,直接正題。個(gè)人博客地址:http://whutzkj.space/

介紹(官方套路) 什么是vuex

Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式(至于什么是狀態(tài)管理模式我就不科普了)。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化。Vuex 也集成到 Vue 的官方調(diào)試工具?devtools extension,提供了諸如零配置的 time-travel 調(diào)試、狀態(tài)快照導(dǎo)入導(dǎo)出等高級調(diào)試功能。

為什么需要vuex

上篇文章說過了,當(dāng)一個(gè)應(yīng)用比較簡單的時(shí)候,組件之間的通信以及交互都不會很多,上篇中介紹的通信方法足夠應(yīng)付大多數(shù)的場景。但是當(dāng)應(yīng)用足夠復(fù)雜,多個(gè)組件共享一個(gè)狀態(tài)的時(shí)候,前面的方法會十分繁瑣混亂并且不易管理。所以我們就需要將組件共享的狀態(tài)抽取成一個(gè)類似全局變量的東西,任何組件都可以get以及set這個(gè)狀態(tài),這樣就可以實(shí)現(xiàn)狀態(tài)的高效管理。另外,通過定義和隔離狀態(tài)管理中的各種概念并強(qiáng)制遵守一定的規(guī)則,我們的代碼將會變得更結(jié)構(gòu)化且易維護(hù)。

核心概念 store

每一個(gè) Vuex 應(yīng)用的核心就是 store(倉庫)。“store”基本上就是一個(gè)容器,它包含著你的應(yīng)用中大部分的狀態(tài) (state)。Vuex 和單純的全局對象有以下兩點(diǎn)不同:

Vuex 的狀態(tài)存儲是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會相應(yīng)地得到高效更新。

你不能直接改變 store 中的狀態(tài)。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用。

如何將store注入我們的應(yīng)用(下面的所有代碼我將以購物車為例)
先將項(xiàng)目結(jié)構(gòu)放出來

// 創(chuàng)建一個(gè)簡單的store
const store = new Vuex.Store({
  state: {
    totalPrice: 0
  },
  mutations: {
    add (state) {
      state.totalPrice++;
    }
  }
})

你可以通過store.state獲取狀態(tài)值,你也可以通過store.commit("add")來改變狀態(tài)。

store.commit("add");
console.log(store.state.totalPrice);  // 1

這里不通過直接修改store.state的值,而是通過提交mutation去變更,主要是為了使得整個(gè)數(shù)據(jù)的變更可以追蹤。舉個(gè)例子:門禁卡,每次進(jìn)出我們刷一下卡系統(tǒng)顯示的是你的名字,知道你來了。刷卡的過程就是你提交的mutation,聲明一聲:你大爺來了,然后系統(tǒng)(倉庫狀態(tài))記錄一下狀態(tài)。后面查詢出入記錄的時(shí)候就有跡可循。

state

state是單一狀態(tài)樹,用一個(gè)對象包含所有應(yīng)用層級的狀態(tài),具有唯一性。(這種話太官方,就是一個(gè)對象,名字叫state。)
state的讀寫就是store中的代碼。由于 Vuex 的狀態(tài)存儲是響應(yīng)式的,所以我們在組件中通過計(jì)算屬性去返回某個(gè)狀態(tài):

// 購物車 shop.vue

或者采用輔助函數(shù)mapstate,這里先用,后面我會講一下原理。

// 購物車 shop.vue

我們之所以可以這么使用,是因?yàn)閂uex 通過 store 選項(xiàng),提供了一種機(jī)制將狀態(tài)從根組件“注入”到每一個(gè)子組件中(需調(diào)用 Vue.use(Vuex)):

// index.js
import Vue from "vue"
import Vuex from "vuex"

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        totalPrice: 0
    },
})
Getter

簡單點(diǎn)介紹getter就是vuex中的計(jì)算屬性。
下面對比一下 computed VS getters

//  shop.vue 
computed: {
   totalPrice() {
       return this.$store.state.totalPrice;
   },
   shopCartList() {
       return this.$store.state.shopCartList;
   }
},
// getters.js
export default {
    expensive(state) {
        return state.shopCartList.filter(shop => {
            return shop.price > 2000
        })
    },
    moreExpensive(state,getters) {
        return getters.expensive.filter(shop => {
            return shop.price > 4000
        })
    }
}

通過上面我們可以看出 計(jì)算屬性computed返回給當(dāng)前的組件或者他的子組件使用的,但是getters將store的state中的值重新計(jì)算后供整個(gè)應(yīng)用使用,但是原理是類似的。同時(shí)從代碼可以看出getter可以接受其他getter當(dāng)做第二個(gè)參數(shù)使用,就像在貴的上面篩選出更貴的。
至于怎么使用getter就比較簡單了,將getters添加到參數(shù)對象中就可以了

// index.js
export default new Vuex.Store({
    state: {
        totalPrice: 0,
        shopCartList: []
    },
    mutations,
    getters
})

調(diào)用getters,兩種方法

// shop.vue 普通方式
computed: {
   expensive() {
      return this.$store.getters.expensive;
   },
   moreExpensive() {
      return this.$store.getters.moreExpensive;
   }
},
// shop.vue 輔助函數(shù)方式
import { mapGetters } from "vuex"
computed: {
   ...mapGetters([
       "expensive",
       "moreExpensive"
   ])
},
Mutation 概念

mutation就是事件類型與事件回調(diào),本身這個(gè)應(yīng)該在前面講比較合適,因?yàn)檫@是更改狀態(tài)的第一步,但是官方按照這個(gè)順序,我們就還是按原樣。
每一個(gè)mutation都會有一個(gè)事件的type和callback,當(dāng)我們store.commit("plus")一個(gè)事件后,vuex會根據(jù)它的type(plus),然后調(diào)用相應(yīng)的callback執(zhí)行增加的操作,然后去變更倉庫中的狀態(tài)。

載荷

同時(shí)你可以向store.commit增加額外的參數(shù),這會被當(dāng)做mutation的載荷playload。

使用常量替代 Mutation 事件類型

這塊其實(shí)很簡單,就是將額外編寫一個(gè)專門存放type的文件引入mutation,將常量作為各個(gè)mutation的事件類型

Mutation 必須是同步函數(shù)

這個(gè)是mutation中最重要的一點(diǎn),如果你在mutation中有異步的回調(diào),那么追蹤記錄就不可能了,這樣就破壞了vuex的初衷。

具體代碼

// mutations.js
import * as types from "./mutation-types"
import Vue from "vue"

export default {
    [types.ADD_TO_SHOPCART](state,payload){
        let allPro = [];        
        state.shopCartList.forEach( (pro) => {
            allPro.push(pro.name);
        })
        if(!payload.num && payload.num != 0){
            Vue.set(payload,"num",1);
        }
        if(!payload.totalPrice){
            Vue.set(payload,"totalPrice",payload.price);
        }

        if(allPro.indexOf(payload.name) < 0){
            state.shopCartList.push(payload);
        }else{
            state.shopCartList.forEach( (pro) => {
                if(pro.name == payload.name){
                    pro.num ++ ;
                    pro.totalPrice = pro.num * pro.price;
                }
            })
        }
        state.totalPrice = state.shopCartList.reduce((sum,value) => {
            return sum + value.totalPrice;        
        },0)
    },
    [types.MINUS_TO_SHOPCART](state,payload){
        let popIndex;
        state.shopCartList.forEach( (pro,index) => {
            if(pro.name == payload.name){
                if(pro.num > 1){
                    pro.num -- ;
                    pro.totalPrice = pro.num * pro.price;
                }else{
                    popIndex = index;                    
                }
            }
        })
        popIndex == 0  && state.shopCartList.splice(popIndex,1);
    }
}
// mutation-types.js
export const ADD_TO_SHOPCART = "ADD_TO_SHOPCART"
export const MINUS_TO_SHOPCART = "MINUS_TO_SHOPCART"
Action 概念

action就是異步提交mutation。Action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對象,但是這個(gè)context對象不是store本身,因?yàn)楹竺娼榻B到的Module會存在局部context和根context兩種。

action: {
  increment (context) {
    context.commit("increment")
  }
}

有個(gè)圖很好的說明了action的具體實(shí)現(xiàn),這里dispatch出action后,再在回調(diào)里面去commit mutation,這樣即便是回調(diào)依然可以追蹤到相關(guān)的狀態(tài)變更記錄。

分發(fā)action

Action 通過 store.dispatch 方法觸發(fā),支持載荷方式和對象方式進(jìn)行分發(fā),這里我自己的項(xiàng)目里面沒有用到action,但是我們可以假設(shè)一個(gè)場景,就是你添加商品的時(shí)候需要請求接口判斷庫存(不過一般都不會這么去設(shè)計(jì)):

actions: {
  check({commit},product){
    getAjax(url).then(res => {
       if(庫存足夠){
         commit( types.ADD_TO_SHOPCART,product )
       }else{
          ....
       }
    })
  }
}

action也是支持嵌套的,是因?yàn)閟tore.dispatch 可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise,并且 store.dispatch 仍舊返回 Promise。

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit("someMutation")
        resolve()
      }, 1000)
    })
  }
}

你可以這么使用

store.dispatch("actionA").then(() => {
  // ...
})

在另外的action中

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch("actionA").then(() => {
      commit("someOtherMutation")
    })
  }
}
Module 概念

module這塊其實(shí)不太想講的,因?yàn)楣俜降奈臋n寫的相當(dāng)清楚。這里就稍微搬弄一波。倉庫雖然可以存放很多東西,但是東西太多了之后也還是會凌亂,所以我們需要分區(qū),module就是將store分成多帶帶的模塊,每個(gè)module享有自己獨(dú)有的state,mutation,action,getter甚至是嵌套的子模塊。
我的代碼中沒有使用module,這里依然使用官方的例子解釋,使用代碼很簡單,看一下就好了:

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 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
模塊的局部狀態(tài)

因?yàn)槊總€(gè)module都有自己的局部狀態(tài),那么必然就會區(qū)分局部狀態(tài)和根狀態(tài),主要注意的也就是這點(diǎn)局部狀態(tài)和根狀態(tài),mutation,action,getter,通過不同的參數(shù)位將局部和根狀態(tài)傳入這里就沒有代碼了,看官方的文檔還是非常清楚的。

命名空間

這個(gè)就是讓模塊有更高封裝度的的一個(gè)屬性 namespaced: true。
這樣這個(gè)模塊的里面的mutation,action這類都會有相應(yīng)的路徑。就像下面的代碼,如果我們?nèi)サ鬾amespaced:true,那么account模塊中的getters,actions,mutations里面的方法都是全局可以訪問的。但是加了namespaced:true,就需要加上對應(yīng)的模塊路徑訪問。

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

      // 模塊內(nèi)容(module assets)
      state: { ... }, // 模塊內(nèi)的狀態(tài)已經(jīng)是嵌套的了,使用 `namespaced` 屬性不會對其產(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"]
          }
        }
      }
    }
  }
})

module里面其他的就不講了。最后講下上文提到的輔助函數(shù),這里以mapstate為例。

輔助函數(shù)mapstate

下面的是mapstate的源碼:

var mapState = normalizeNamespace(function (namespace, states) {
  var res = {};
  normalizeMap(states).forEach(function (ref) {
    var key = ref.key;
    var val = ref.val;

    res[key] = function mappedState () {
      var state = this.$store.state;
      var getters = this.$store.getters;
      if (namespace) {
        var module = getModuleByNamespace(this.$store, "mapState", namespace);
        if (!module) {
          return
        }
        state = module.context.state;
        getters = module.context.getters;
      }
      return typeof val === "function"
        ? val.call(this, state, getters)
        : state[val]
    };
    // mark vuex getter for devtools
    res[key].vuex = true;
  });
  return res
});

這里我先將這個(gè)方法簡化一下

var mapState = normalizeNamespace(fn);

我們先看上面的代碼mapstate首先調(diào)用的是normalizeNamespace這個(gè)函數(shù),我們再看normalizeNamespace這個(gè)方法里面的邏輯:
這個(gè)函數(shù)接受一個(gè)方法作為參數(shù),返回一個(gè)函數(shù),這個(gè)函數(shù)也就mapstate。mapsate接收兩個(gè)參數(shù)namespace和map,這里的namespace就是上面module當(dāng)中介紹到的命名空間里面的namespace。當(dāng)namespace不傳的時(shí)候就將第一個(gè)參數(shù)(映射的對象)賦給map,或者傳入namespace就對其進(jìn)行類型判斷以及格式校驗(yàn)后,返回傳入的fn的調(diào)用。

function normalizeNamespace (fn) {
  return function (namespace, map) {
    if (typeof namespace !== "string") {
      map = namespace;
      namespace = "";
    } else if (namespace.charAt(namespace.length - 1) !== "/") {
      namespace += "/";
    }
    return fn(namespace, map)
  }
}

然后我們具體看傳入的fn這個(gè)函數(shù)具體干了什么,首先定義一個(gè)空res對象,然后調(diào)用normalizeMap(這個(gè)函數(shù)的解析在下面)這個(gè)方法將states轉(zhuǎn)化為每項(xiàng)都是{ key: key, val: key }格式的對象數(shù)組,然后foreach遍歷。
遍歷里面將上面的對象數(shù)組的key,val重新整理進(jìn)入res中。mappedState具體里面的邏輯如下:
默認(rèn)進(jìn)來state和getters是全局倉庫里面的,然后再去判斷是否有namespace這個(gè),如果有將對應(yīng)的那個(gè)module中的state和getters覆蓋掉全局的那個(gè),最后判斷val如果是函數(shù),就直接調(diào)用這個(gè)函數(shù),并且將前面定義好的state以及getters當(dāng)做參數(shù)傳入,如果不是函數(shù)則直接取值。
res[key].vuex = true;這行就是提供給插件使用的。

// mapstate中傳入的fn
function (namespace, states) {
  var res = {};
  normalizeMap(states).forEach(function (ref) {
    var key = ref.key;
    var val = ref.val;

    res[key] = function mappedState () {
      var state = this.$store.state;
      var getters = this.$store.getters;
      if (namespace) {
        var module = getModuleByNamespace(this.$store, "mapState",namespace);
        if (!module) {
          return
        }
        state = module.context.state;
        getters = module.context.getters;
      }
      return typeof val === "function"
        ? val.call(this, state, getters)
        : state[val]
    };
    // mark vuex getter for devtools
    res[key].vuex = true;
  });
  return res
}

normalizeMap這個(gè)方法判斷了map書否是數(shù)組,如果是就將map中每一項(xiàng)轉(zhuǎn)化為{ key: key, val: key }的對象,否則傳入的 map 就是一個(gè)對象(因?yàn)閙apstate傳入的參數(shù)不是數(shù)組就是對象),那就調(diào)用Object.keys獲取map的所有key值,然后key數(shù)組再次遍歷轉(zhuǎn)化為{ key: key, val: map[key] }這個(gè)對象,最后將這個(gè)對象數(shù)組作為normalizeMap的返回值。

// normalizeMap
function normalizeMap (map) {
  return Array.isArray(map)
    ? map.map(function (key) { return ({ key: key, val: key }); })
    : Object.keys(map).map(function (key) { return ({ key: key, val: map[key] }); })
}

差不多就是這些啦,其他的輔助函數(shù)也都是類似的,有興趣的可以去官網(wǎng)看看源碼。有錯(cuò)希望大家及時(shí)指出,我只是代碼的搬運(yùn)工,哈哈...

相關(guān)文檔:
vuex : https://vuex.vuejs.org/zh-cn/
vuex gitHub : https://github.com/vuejs/vuex...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89284.html

相關(guān)文章

  • 瞎說系列之Object.assign入門

    摘要:如果只傳入了一個(gè)參數(shù),則該方法會直接返回該參數(shù)。如果傳入的參數(shù)不是對象,原始類型會被包裝為對象。和無法被轉(zhuǎn)為對象,所以如果把它們兩個(gè)作為目標(biāo)對象則會報(bào)錯(cuò)。注意首先基本數(shù)據(jù)類型會被包裝成對象,和會被忽略。后續(xù)的內(nèi)容,敬請期待。 前言 過去的一個(gè)多月新接手了一個(gè)公司的老項(xiàng)目,在實(shí)現(xiàn)新需求的同時(shí)還需要對有些地方進(jìn)行重構(gòu),故而導(dǎo)致了沒時(shí)間更新文章。最近趁著周末更新一篇關(guān)于Object.assi...

    jk_v1 評論0 收藏0
  • 阿里巴巴王堅(jiān):要像規(guī)劃土地資源一樣規(guī)劃數(shù)據(jù)資源

    摘要:日消息,中國深圳領(lǐng)袖峰會召開。王堅(jiān)還在對話中介紹了阿里的城市大腦地鐵電網(wǎng)實(shí)際上是一個(gè)城市發(fā)展最最重要的東西,今天有數(shù)字經(jīng)濟(jì)或數(shù)字中國的時(shí)候,一個(gè)城市要像規(guī)劃土地資源一樣來規(guī)劃一個(gè)城市的數(shù)據(jù)資源。25日消息,2018中國(深圳)IT領(lǐng)袖峰會召開。數(shù)字中國聯(lián)合會主席吳鷹作為主持人,富士康科技集團(tuán)董事長郭臺銘,神州數(shù)碼控股有限公司董事局主席、公司董事長郭為,賽富亞洲投資基金創(chuàng)始管理合伙人閻焱,阿里...

    wwq0327 評論0 收藏0
  • 阿里巴巴集團(tuán)王堅(jiān):要像規(guī)劃土地資源一樣規(guī)劃數(shù)據(jù)資源

    摘要:王堅(jiān)還在對話中介紹了阿里的城市大腦地鐵電網(wǎng)實(shí)際上是一個(gè)城市發(fā)展最最重要的東西,今天有數(shù)字經(jīng)濟(jì)或數(shù)字中國的時(shí)候,一個(gè)城市要像規(guī)劃土地資源一樣來規(guī)劃一個(gè)城市的數(shù)據(jù)資源。今天2018中國(深圳)IT領(lǐng)袖峰會召開。數(shù)字中國聯(lián)合會主席吳鷹作為主持人,富士康科技集團(tuán)董事長郭臺銘,神州數(shù)碼控股有限公司董事局主席、公司董事長郭為,賽富亞洲投資基金創(chuàng)始管理合伙人閻焱,阿里巴巴集團(tuán)技術(shù)委員會主席王堅(jiān)作為對話嘉賓...

    Rocture 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<