vue快速上手-3

8. vue插件

什么是Vue-Devtools?
官方的說法是它允許你在一個更友好的界面中審查和調(diào)試 Vue 應(yīng)用。在網(wǎng)上查了沒有太明確的說法。說白了就是幫助前端開發(fā)vue的一個應(yīng)用,在Components你可以更好的看到組件信息變量和方法,在vuex中你可以查看到state,mutations,actions, getters等。在Events中你能看到你的所有事件方法。下面我們來學(xué)習(xí)下怎么安裝它。
步驟一:訪問該地址:vue調(diào)試工具插件 ,下載vue調(diào)試工具插件。直接點擊推薦下載,相關(guān)文件就會下載下來。

image

步驟二:

將下載的文件進(jìn)行解壓,解壓完之后,文件內(nèi)容如下:

image

打開谷歌瀏覽器,點擊右上角 ==》選擇更多工具按鈕 ==》選擇擴展程序

然后將之前解壓的Vue.js Devtools_5.3.3_chrome.zzzmh.cn.crx文件拖拽到擴展程序界面,按照對應(yīng)提示點擊確認(rèn)即可。

9. vuex

VueX是適用于在Vue項目開發(fā)時使用的狀態(tài)管理工具。試想一下,如果在一個項目開發(fā)中頻繁的使用組件傳參的方式來同步data中的值,一旦項目變得很龐大,管理和維護(hù)這些值將是相當(dāng)棘手的工作。為此,Vue為這些被多個組件頻繁使用的值提供了一個統(tǒng)一管理的工具——VueX。在具有VueX的Vue項目中,我們只需要把這些值定義在VueX中,即可在整個Vue項目的組件中使用。

Vuex 可以幫助我們管理共享狀態(tài),并附帶了更多的概念和框架。這需要對短期和長期效益進(jìn)行權(quán)衡。

如果不打算開發(fā)大型單頁應(yīng)用,應(yīng)用夠簡單,最好不要使用 Vuex。一個簡單的 store 模式就足夠了。但是,如果需要構(gòu)建一個中大型單頁應(yīng)用,就要考慮如何更好地在組件外部管理狀態(tài),Vuex 是不錯的選擇。

9.1 安裝Vuex

npm install vuex --save

為了項目格式便于維護(hù)和相對規(guī)范一點,我們先在 目錄下建立一個 store 文件夾,并且在下面建立一個 store.js 文件


image

9.2 創(chuàng)建store

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
    state: {
      count: 0
    }
})
export default store

store是Vuex.Store這個構(gòu)造函數(shù)new出來的實例。在構(gòu)造函數(shù)中可以傳一個對象參數(shù)。這個參數(shù)中可以包含5個對象:

1.state – 存放狀態(tài)

2.getters – state的計算屬性

3.mutations – 更改狀態(tài)的邏輯,同步操作

4.actions – 提交mutation,異步操作

5.mudules – 將store模塊化

關(guān)于store,需要先記住兩點:

  1. store 中存儲的狀態(tài)是響應(yīng)式的,當(dāng)組件從store中讀取狀態(tài)時,如果store中的狀態(tài)發(fā)生了改變,那么相應(yīng)的組件也會得到更新;

  2. 不能直接改變store中的狀態(tài)。改變store中的狀態(tài)的唯一途徑是提交(commit)mutations。這樣使得我們可以方便地跟蹤每一個狀態(tài)的變化。

9.2.1 一個完整的store的結(jié)構(gòu)是這樣的

const store = new Vuex.Store({
  state: {
    // 存放狀態(tài)
  },
  getters: {
    // state的計算屬性
  },
  mutations: {
    // 更改state中狀態(tài)的邏輯,同步操作
  },
  actions: {
    // 提交mutation,異步操作
  },
  // 如果將store分成一個個的模塊的話,則需要用到modules。
   //然后在每一個module中寫state, getters, mutations, actions等。
  modules: {
    a: moduleA,
    b: moduleB,
    // ...
  }
});

9.3 state

state上存放的,說的簡單一些就是變量,也就是所謂的狀態(tài)。沒有使用 state 的時候,我們都是直接在 data 中進(jìn)行初始化的,但是有了 state 之后,我們就把 data 上的數(shù)據(jù)轉(zhuǎn)移到 state 上去了。另外有些狀態(tài)是組件私有的狀態(tài),稱為組件的局部狀態(tài),我們不需要把這部分狀態(tài)放在store中去。

9.3.1 如何在組件中獲取vuex狀態(tài)

由于vuex的狀態(tài)是響應(yīng)式的,所以從store中讀取狀態(tài)的的方法是在組件的計算屬性中返回某個狀態(tài)。

import store from 'store';
const Counter = {  
  template: `<div>{{ count }}</div>`,  
  computed: {    
    count () {      // 獲取store中的狀態(tài)      
      return store.state.count;   
   }  
  }
}

這樣,組件中的狀態(tài)就與store中的狀態(tài)關(guān)聯(lián)起來了。每當(dāng)store.state.count發(fā)生變化時,都會重新求取計算屬性,從而更新DOM。

然而,每個組件中都需要反復(fù)倒入store??梢詫tore注入到vue實例對象中去,這樣每一個子組件中都可以直接獲取store中的狀態(tài),而不需要反復(fù)的倒入store了。

const app = new Vue({  
  el: '#app',  // 把 store 對象注入到了  store,  
  components: { Counter },  
  template: `<div><counter></counter></div>    `
});

這樣可以在子組件中使用this.$store.state.count訪問到state里面的count這個狀態(tài)

const Counter = {  
  template: `<div>{{ count }}</div>`,  
  computed: {    
    count () {      // 獲取store中的狀態(tài)      
      return this.$store.state.count;    
    }  
  }
}

9.3.2 mapState

推薦使用展開運算符:
mapState 等四個函數(shù)返回的都是一個對象。通常,我們需要使用一個工具函數(shù)將多個對象合并為一個,以使我們可以將最終對象傳給 computed 屬性。但是有了對象展開運算符,我們就可以進(jìn)行簡化寫法。
當(dāng)一個組件獲取多種狀態(tài)的時候,則在計算屬性中要寫多個函數(shù)。為了方便,可以使用mapState輔助函數(shù)來幫我們生成計算屬性。

import { mapState } from  'vuex';
export default {
  // ...
  data (){
    localState: 1
  }
  computed: mapState({
    // 此處的state即為store里面的state
    count: state => state.count,
    //'count'等同于 ‘state => state.count’
    countAlias: 'count',
    countPlus (state){
    // 使用普通函數(shù)是為了保證this指向組件對象
      return state.count + this.localState;
    }
  })
}
//上面是通過mapState的對象來賦值的,還可以通過mapState的數(shù)組來賦值
computed: mapState(['count']);
//這種方式很簡潔,但是組件中的state的名稱就跟store中映射過來的同名

對象擴展運算符

mapState 函數(shù)返回的是一個對象,為了將它里面的計算屬性與組件本身的局部計算屬性組合起來,需要用到對象擴展運算符。

computed: {
  ...mapState ({
      
  })
}

這樣,mapState中的計算屬性就與localState計算屬性混合一起了。

9.4 getters

有時候我們需要從 store 中的 state 中派生出一些狀態(tài),例如對列表進(jìn)行過濾并計數(shù)。此時可以用到getters,getters可以看作是store的計算屬性,其參數(shù)為state。

const store = new Vuex.Store({
  state: {
    todos: [
      {id: 1, text: 'reading', done: true},
      {id: 2, text: 'playBastketball', done: false}
    ]
  },
  getters: {
    doneTodos: state => {
      return state.todos.filter(todo => todo.done);
    }
  }
});

9.4.1 獲取getters里面的狀態(tài),方法一

store.getters.doneTodos //  [{ id: 1, text: 'reading', done: true }]
//在組件中,則要寫在計算屬性中,
computed: {
  doneTodos () {
    return this.$store.getters.doneTodos;
  }
}

9.4.2 使用mapGetters獲取getters里面的狀態(tài):方法二

import {mapState, mapGetters} from 'vuex';
computed: {
...mapState(['increment']),
...mapGetters(['doneTodos'])
}

9.5 mutations

mutations里面是如何更改state中狀態(tài)的邏輯。更改Vuex中的state的唯一方法是,提交mutation,即store.commit(‘increment’)。

9.5.1 提交載荷(payload)

可以向commit傳入額外的參數(shù),即mutation的載荷。

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

payload還可以是一個對象。

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

還可以使用type屬性來提交mutation。

store.commit({
  type: 'increment',
  amount: 10
});
// mutations保持不變
mutations: {
  increment(state, payload){
    state.count += payload.amount;
  }
}

注意:mutation必須是同步函數(shù),不能是異步的,這是為了調(diào)試的方便。

9.5.2 在組件中提交mutations

那么mutation應(yīng)該在哪里提交呢? 因為js是基于事件驅(qū)動的,所以改變狀態(tài)的邏輯肯定是由事件來驅(qū)動的,所以store.commit(‘increment’)是在組件的methods中來執(zhí)行的。

方法1: 在組件的methods中提交

methods: {
  increment(){
    this.$store.commit('increment');
  }
}

方法2: 使用mapMutations

用 mapMutations 輔助函數(shù)將組件中的 methods 映射為 store.commit 調(diào)用。

import { mapMutations} from 'vuex';
export default {
  // ...
  methods: {
    ...mapMutaions([
    'increment' // 映射 this.increment() 為 this.$store.commit('increment')
  ]),
  ...mapMutaions([
      add: 'increment' // 映射 this.add() 為 this.$store.commit('increment')
    ])
    }
}
 
// 因為mutation相當(dāng)于一個method,所以在組件中,可以這樣來使用
<button @click="increment">+</button>

9.6 actions

因為mutations中只能是同步操作,但是在實際的項目中,會有異步操作,那么actions就是為了異步操作而設(shè)置的。這樣,就變成了在action中去提交mutation,然后在組件的methods中去提交action。只是提交actions的時候使用的是dispatch函數(shù),而mutations則是用commit函數(shù)。

9.6.1 一個簡單的action

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state){
      state.count++;
    }
  },
  actions: {
    increment(context){
      context.commit('increment');
    }
    /* 可以用參數(shù)結(jié)構(gòu)的方法來寫action
     increment({commit}){
     commit('increment');
     }
     */
  }
});
 
// action函數(shù)接受一個context參數(shù),這個context具有與store實例相同的方法和屬性。
 
// 分發(fā)action
store.dispatch('increment');

action同樣支持payload和對象方式來分發(fā),格式跟commit是一樣的,不再贅述。

9.6.2 在組件中分發(fā)action

方法1: 在組件的methods中,使用this.$store.dispatch(‘increment’)。

方法2: 使用mapActions,跟mapMutations是類似的。

import { mapActions } from 'vuex'
export default {
  // ...
  methods: {
    ...mapActions([
    'increment' // 映射 this.increment() 為 this.$store.dispatch('increment')
  ]),
  ...mapActions({
  add: 'increment' // 映射 this.add() 為 this.$store.dispatch('increment')
})
}
}
 
// 同樣在組件中,可以這樣來使用
<button @click="increment">+</button>

9.6.3 組合actions

因為action是異步的,那么我們需要知道這個異步函數(shù)什么時候結(jié)束,以及等到其執(zhí)行后,會利用某個action的結(jié)果。這個可以使用promise來實現(xiàn)。在一個action中返回一個promise,然后使用then()回調(diào)函數(shù)來處理這個action返回的結(jié)果。

actions:{
  actionA({commit}){
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation');
        resolve();
      },1000);
    })
  }
}
 
// 這樣就可以操作actionA返回的結(jié)果了
store.dispatch('actionA').then(() => {
  // dosomething ...
});
 
// 也可以在另一個action中使用actionA的結(jié)果
actions: {
  // ...
  actionB({ dispatch, commit }){
    return dispatch('actionA').then(() => {
      commit('someOtherMutation');
    })
  }
}

9.7 mudules

module是為了將store拆分后的一個個小模塊,這么做的目的是因為當(dāng)store很大的時候,分成模塊的話,方便管理。

9.7.1 每個module擁有自己的state, getters, mutation, action

const moduleA = {
    state: {...},
    getters: {...},
    mutations: {....},
  actions: {...}
}
 
const moduleB = {
    state: {...},
    getters: {...},
    mutations: {....},
  actions: {...}
}
 
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
});
 
store.state.a // 獲取moduleA的狀態(tài)
store.state.b // 獲取moduleB的狀態(tài)

附:項目結(jié)構(gòu)

Vuex 不限制代碼結(jié)構(gòu)。但是規(guī)定了一些需要遵守的規(guī)則:

  1. 應(yīng)用層級的狀態(tài)應(yīng)該集中到單個 store 對象中。
  2. 提交 mutation 是更改狀態(tài)的唯一方法,并且這個過程是同步的。
  3. 異步邏輯都應(yīng)該封裝到 action 里面。

只要你遵守以上規(guī)則,如何組織代碼隨你便。如果 store 文件太大,只需將 action、mutation 和 getter 分割到單獨的文件。

對于大型應(yīng)用,我們會希望把 Vuex 相關(guān)代碼分割到模塊中。下面是項目結(jié)構(gòu)示例:


項目結(jié)構(gòu)示例

9.8 Vuex持久化存儲之vuex-persist

Vuex 的狀態(tài)存儲并不能持久化。也就是說當(dāng)你存儲在 Vuex 中的 store 里的數(shù)據(jù),只要一刷新頁面,數(shù)據(jù)就丟失了。

引入vuex-persist 插件,它就是為 Vuex 持久化存儲而生的一個插件。不需要你手動存取 storage ,而是直接將狀態(tài)保存至 cookie 或者 localStorage 中。具體用法如下:

安裝:

npm install --save vuex-persistoryarn add vuex-persist

引入:

import VuexPersistence from 'vuex-persist'

先創(chuàng)建一個對象并進(jìn)行配置:

const vuexLocal = new VuexPersistence({
    storage: window.localStorage
})

引入進(jìn)vuex插件:

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

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

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