摘要:但是,當(dāng)應(yīng)用變得很大時(shí),對(duì)象會(huì)變得臃腫不堪。允許我們將分割到模塊。每個(gè)模塊擁有自己的甚至是嵌套子模塊。你可以通過(guò)添加前綴或后綴的方式隔離各模塊,以避免名稱(chēng)沖突。
vuex簡(jiǎn)介前言:在使用vue開(kāi)發(fā)的時(shí)候數(shù)據(jù)一版通過(guò)事件分發(fā)的方式進(jìn)行,在vue1.x中組件中數(shù)據(jù)交互主要包含有:
子組件事件派發(fā):$emit(向父級(jí)),$dispatch(沿著父級(jí)向上冒泡)
父組件通過(guò)$on監(jiān)聽(tīng)到之后進(jìn)行相應(yīng)的操作
當(dāng)有兄弟組件需要監(jiān)聽(tīng)事件,父組件通過(guò)$broadcast向下廣播。
vue2.x中取消了$dispatch,$broadcast,要實(shí)現(xiàn)組件之前的交互就非常蛋疼了,首先要不停的通過(guò)$emit派發(fā)到需要獲取到這個(gè)事件的父級(jí),然后父級(jí)通過(guò)$ref來(lái)調(diào)用相應(yīng)的子組件的方法,單想想就容易心態(tài)爆炸。解決辦法有2:
在根目錄下data里新建一個(gè)vue對(duì)象作為eventHander,所有的事件通過(guò)這個(gè)新建的vue對(duì)象進(jìn)行監(jiān)聽(tīng)派發(fā),具體就不進(jìn)行描述了送上關(guān)鍵字:this.$root.eventHander.$on、this.$root.eventHander.$emit;
全局狀態(tài)管理工具vuex,什么是vuex?借助官網(wǎng)的一句話(huà):采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。;
借助一張圖片,簡(jiǎn)短的對(duì)vuex的狀態(tài)管理進(jìn)行一個(gè)描述
從上圖可以看出vuex主要包含actions、mutations、state
交互過(guò)程中,渲染:vue components根據(jù)state進(jìn)行渲染,響應(yīng):通過(guò)觸發(fā)actions相關(guān)事件調(diào)用mutations相關(guān)函數(shù),mutations對(duì)state進(jìn)行改變,state的改變引發(fā)vue components的重繪
狀態(tài)的統(tǒng)一管理對(duì)大型項(xiàng)目提供了相當(dāng)多的便利,數(shù)據(jù)的操作都可以通過(guò)vuex來(lái)進(jìn)行,小型項(xiàng)目組件并不復(fù)雜,數(shù)據(jù)的交互層級(jí)不高,因此并不建議使用vuex進(jìn)行數(shù)據(jù)交互
在對(duì)vuex進(jìn)行描述之前送上vuex官網(wǎng)飛機(jī)票一張
核心概念之statestate定義state里存儲(chǔ)所有應(yīng)用層級(jí)的信息。是作為唯一的一個(gè)數(shù)據(jù)源存在.
const store = new Vuex.Store({ state: { count: 0 } }) //上面的例子就定義了一個(gè)state,state存有一個(gè)變量countstate獲取
//網(wǎng)頁(yè)直接通過(guò)script標(biāo)簽引入的方式不需要進(jìn)行注冊(cè),模塊化構(gòu)建一定要進(jìn)行Vue.use(Vuex)組件注冊(cè) //...state定義 //ps:注意,state相關(guān)數(shù)據(jù)是寫(xiě)在computed內(nèi),不是寫(xiě)在data內(nèi) new Vue({ el: "#app", template: `核心概念之mutations{{count}}` computed: { count() { return this.$store.state.count } }, store }) //首先將store注入到組件內(nèi)部,調(diào)用可直接通過(guò)this.$store.state獲取相應(yīng)的值 //當(dāng)數(shù)組需要獲取多個(gè)狀態(tài)值時(shí)this.$store.state前綴就需要寫(xiě)的很多,容易冗余,利用mapState輔助函數(shù)可以很好的解決這個(gè)問(wèn)題 import { mapState } from "vuex" //在直接標(biāo)簽引入的情況下用mapState = vuex.mapState; computed: mapState({ count: state => state.count, countAlias: "count", // 為了能夠使用 `this` 獲取局部狀態(tài),必須使用常規(guī)函數(shù),因?yàn)榧^函數(shù)會(huì)進(jìn)行this綁定 countPlusLocalState (state) { return state.count + this.localCount } }) //當(dāng)映射的計(jì)算屬性的名稱(chēng)與 state 的子節(jié)點(diǎn)名稱(chēng)相同時(shí),我們也可以給 mapState 傳一個(gè)字符串?dāng)?shù)組 computed: mapState([ // 映射 this.count 為 store.state.count "count" ]) //當(dāng)需要與當(dāng)前組件屬性共同使用的時(shí)候,可采用es6/7的對(duì)象展開(kāi)符 computed: { localComputed () { /* ... */ }, // 使用對(duì)象展開(kāi)運(yùn)算符將此對(duì)象混入到外部對(duì)象中 ...mapState({ // ... }) }
更改store中的state的唯一方法就是通過(guò)mutation,每個(gè)mutation都像是一個(gè)事件監(jiān)聽(tīng),等待調(diào)用的觀察者。其由一個(gè)事件類(lèi)型和一個(gè)回調(diào)函數(shù)構(gòu)成,回調(diào)函數(shù)對(duì)state進(jìn)行修改,事件類(lèi)型名稱(chēng)作為事件調(diào)用的名稱(chēng);
//聲明 const store = new Vuex.Store({ //... mutations: { increment (state) { // 變更狀態(tài) state.count++ } } }) //喚起 store.commit("increment")提交荷載
提交荷載可以理解為store.commit傳遞的額外參數(shù)
// ... mutations: { increment (state, n) { state.count += n } } store.commit("increment", 10) //在大多數(shù)情況下,載荷應(yīng)該是一個(gè)對(duì)象,這樣可以包含多個(gè)字段并且記錄的 mutation 會(huì)更易讀: // ... mutations: { increment (state, payload) { state.count += payload.amount } } store.commit("increment", { amount: 10 }) //對(duì)象風(fēng)格的提交方式 store.commit({ type: "increment", amount: 10 })相應(yīng)規(guī)則
最好提前在你的 store 中初始化好所有所需屬性。
當(dāng)需要在對(duì)象上添加新屬性時(shí),你應(yīng)該
使用Vue.set(state.obj,"newProp","xxx")
state.obj = { ...state.obj, newProp: 123 }
使用常量代替mutation事件類(lèi)型這么做的好處是對(duì)state的操作接口一目了然,全部展現(xiàn)在mutation-types文件夾中,便于大項(xiàng)目的協(xié)作。當(dāng)然這不是必須的。
// mutation-types.js export const SOME_MUTATION = "SOME_MUTATION" // store.js import Vuex from "vuex" import { SOME_MUTATION } from "./mutation-types" const store = new Vuex.Store({ state: { ... }, mutations: { // 我們可以使用 ES2015 風(fēng)格的計(jì)算屬性命名功能來(lái)使用一個(gè)常量作為函數(shù)名 [SOME_MUTATION] (state) { // mutate state } } })mutation必須是同步函數(shù)
組件的mapMutations因?yàn)楫惒胶瘮?shù)會(huì)導(dǎo)致?tīng)顟B(tài)的不確定性,造成運(yùn)行和調(diào)試的出路,這里就不進(jìn)行展開(kāi)了。
import { mapMutations } from "vuex" export default { // ... methods: { ...mapMutations([ //type1 "increment" // 映射 this.increment() 為 this.$store.commit("increment") ]), //type2 ...mapMutations({ add: "increment" // 映射 this.add() 為 this.$store.commit("increment") }) } }核心概念之a(chǎn)ctions
上一章我們有提到mutation是沒(méi)有異步操作的,因此異步操作需要用到action,注意action提交的mutation而不是直接處理state
const store = new Vuex.Store({ //... actions: { //context與store對(duì)象具有相同的方法和參數(shù),但。。不是store本身 increment (context) { context.commit("increment") } }, //也可以寫(xiě)成 actions: { increment ({ commit }) { commit("increment") } } })分發(fā) Action
store.dispatch("increment"); //action同樣支持荷載方式,和mutation差不多 // 以載荷形式分發(fā) store.dispatch("incrementAsync", { amount: 10 }) // 以對(duì)象形式分發(fā) store.dispatch({ type: "incrementAsync", amount: 10 })組件中分發(fā) Action
import { mapActions } from "vuex" export default { // ... methods: { ...mapActions([ "increment" // 映射 this.increment() 為 this.$store.dispatch("increment") ]), ...mapActions({ add: "increment" // 映射 this.add() 為 this.$store.dispatch("increment") }) } }組合 Actions
因?yàn)閍ction是異步的,因此組合多個(gè)action將是一個(gè)大問(wèn)題,要解決這個(gè)問(wèn)題這里引用了promise對(duì)象。通過(guò)dispath返回的promise對(duì)象進(jìn)行操作,達(dá)成順序執(zhí)行
//A進(jìn)行promise對(duì)象返回 actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit("someMutation") resolve() }, 1000) }) } } //通過(guò)dispatch后的返回值執(zhí)行異步操作 store.dispatch("actionA").then(() => { // ... }) //actions之間的互相調(diào)用 actions: { // ... actionB ({ dispatch, commit }) { return dispatch("actionA").then(() => { commit("someOtherMutation") }) } } //也可以通過(guò)async/await屬性組合(await只能在async函數(shù)內(nèi)部運(yùn)行)action: actions: { async actionA ({ commit }) { commit("gotData", await getData()) }, async actionB ({ dispatch, commit }) { await dispatch("actionA") // 等待 actionA 完成 commit("gotOtherData", await getOtherData()) } }核心概念之getter
有時(shí)候我們需要從 store 中的 state 中派生出一些狀態(tài)(即對(duì)state進(jìn)行一些操作過(guò)后得到的狀態(tài)),例如對(duì)列表進(jìn)行過(guò)濾并計(jì)數(shù):
//常規(guī)做法,當(dāng)其他component需要用到時(shí)代碼就會(huì)出現(xiàn)冗余 computed: { doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length } } //Vuex 允許我們?cè)?store 中定義『getters』(可以認(rèn)為是 store 的計(jì)算屬性)。Getters 接受 state 作為其第一個(gè)參數(shù) const store = new Vuex.Store({ state: { todos: [ { id: 1, text: "...", done: true }, { id: 2, text: "...", done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } }) //Getters 也可以接受其他 getters 作為第二個(gè)參數(shù) getters: { // ... doneTodosCount: (state, getters) => { return getters.doneTodos.length } } store.getters.doneTodosCount // -> 1 //組件中使用 computed: { doneTodosCount () { return this.$store.getters.doneTodosCount } }mapGetters 輔助函數(shù)
和之前一樣的輔助映射函數(shù)一毛一樣
import { mapGetters } from "vuex" export default { // ... computed: { // 使用對(duì)象展開(kāi)運(yùn)算符將 getters 混入 computed 對(duì)象中 ...mapGetters([ "doneTodosCount", "anotherGetter", // ... ]) mapGetters({ // 映射 this.doneCount 為 store.getters.doneTodosCount doneCount: "doneTodosCount" }) } }核心概念之module
使用單一狀態(tài)樹(shù),導(dǎo)致應(yīng)用的所有狀態(tài)集中到一個(gè)很大的對(duì)象。但是,當(dāng)應(yīng)用變得很大時(shí),store 對(duì)象會(huì)變得臃腫不堪。
Vuex 允許我們將 store 分割到模塊(module)。每個(gè)模塊擁有自己的 state、mutation、action、getters、甚至是嵌套子模塊。
module定義//狀態(tài)篇 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)module局部狀態(tài)
對(duì)于模塊內(nèi)部的 mutation 和 getter,接收的第一個(gè)參數(shù)是模塊的局部狀態(tài)。
//即此狀態(tài)為moduleA的state const moduleA = { state: { count: 0 }, mutations: { increment (state) { // state 模塊的局部狀態(tài) state.count++ } }, //對(duì)于模塊內(nèi)部的 getter,根節(jié)點(diǎn)狀態(tài)會(huì)作為第三個(gè)參數(shù): getters: { doubleCount (state, getters, rootState) { return state.count * 2 } } }, // 同樣,對(duì)于模塊內(nèi)部的 action,context.state 是局部狀態(tài),根節(jié)點(diǎn)的狀態(tài)是 context.rootState這就是之前action的context不等于當(dāng)前store對(duì)象的原因 actions: { incrementIfOddOnRootSum ({ state, commit, rootState }) { if ((state.count + rootState.count) % 2 === 1) { commit("increment") } } }命名空間
模塊內(nèi)部的 action、mutation、和 getter 現(xiàn)在仍然注冊(cè)在全局命名空間——這樣保證了多個(gè)模塊能夠響應(yīng)同一 mutation 或 action。你可以通過(guò)添加前綴或后綴的方式隔離各模塊,以避免名稱(chēng)沖突。你也可能希望寫(xiě)出一個(gè)可復(fù)用的模塊,其使用環(huán)境不可控。例如,我們想創(chuàng)建一個(gè) todos 模塊:
// types.js // 定義 getter、action、和 mutation 的名稱(chēng)為常量,以模塊名 `todos` 為前綴 export const DONE_COUNT = "todos/DONE_COUNT" export const FETCH_ALL = "todos/FETCH_ALL" export const TOGGLE_DONE = "todos/TOGGLE_DONE" // modules/todos.js import * as types from "../types" // 使用添加了前綴的名稱(chēng)定義 getter、action 和 mutation const todosModule = { state: { todos: [] }, getters: { [types.DONE_COUNT] (state) { // ... } }, actions: { [types.FETCH_ALL] (context, payload) { // ... } }, mutations: { [types.TOGGLE_DONE] (state, payload) { // ... } } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82532.html
摘要:如果不熟悉,在這個(gè)教程里面,我們會(huì)通過(guò)構(gòu)建一個(gè)筆記應(yīng)用來(lái)學(xué)習(xí)怎么用。這個(gè)是我們要構(gòu)建的筆記應(yīng)用的截圖你可以從下載源碼,這里是的地址。每當(dāng)用戶(hù)點(diǎn)擊筆記列表中的某一條時(shí),組件會(huì)調(diào)用來(lái)分發(fā)這個(gè)會(huì)把當(dāng)前選中的筆記設(shè)為。 原文:Learn Vuex by Building a Notes App,有刪改。 本文假設(shè)讀者熟悉 Vuex 文檔 的內(nèi)容。如果不熟悉,you definitely sho...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇下的使用方法,傳送門(mén)使用構(gòu)建單頁(yè)應(yīng)用新篇華麗的分割線(xiàn)原文地址前言在最近學(xué)習(xí)的時(shí)候,看到國(guó)外一篇講述了如何使用和來(lái)構(gòu)建一個(gè)簡(jiǎn)單筆記的單頁(yè)應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇 vue2.0 下的 vuex 使用方法,傳送門(mén):使用 Vuex + Vue.js 構(gòu)建單頁(yè)應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇下的使用方法,傳送門(mén)使用構(gòu)建單頁(yè)應(yīng)用新篇華麗的分割線(xiàn)原文地址前言在最近學(xué)習(xí)的時(shí)候,看到國(guó)外一篇講述了如何使用和來(lái)構(gòu)建一個(gè)簡(jiǎn)單筆記的單頁(yè)應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇 vue2.0 下的 vuex 使用方法,傳送門(mén):使用 Vuex + Vue.js 構(gòu)建單頁(yè)應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇下的使用方法,傳送門(mén)使用構(gòu)建單頁(yè)應(yīng)用新篇華麗的分割線(xiàn)原文地址前言在最近學(xué)習(xí)的時(shí)候,看到國(guó)外一篇講述了如何使用和來(lái)構(gòu)建一個(gè)簡(jiǎn)單筆記的單頁(yè)應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇 vue2.0 下的 vuex 使用方法,傳送門(mén):使用 Vuex + Vue.js 構(gòu)建單頁(yè)應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇下的使用方法,傳送門(mén)使用構(gòu)建單頁(yè)應(yīng)用新篇華麗的分割線(xiàn)原文地址前言在最近學(xué)習(xí)的時(shí)候,看到國(guó)外一篇講述了如何使用和來(lái)構(gòu)建一個(gè)簡(jiǎn)單筆記的單頁(yè)應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇 vue2.0 下的 vuex 使用方法,傳送門(mén):使用 Vuex + Vue.js 構(gòu)建單頁(yè)應(yīng)用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇下的使用方法,傳送門(mén)使用構(gòu)建單頁(yè)應(yīng)用新篇華麗的分割線(xiàn)原文地址前言在最近學(xué)習(xí)的時(shí)候,看到國(guó)外一篇講述了如何使用和來(lái)構(gòu)建一個(gè)簡(jiǎn)單筆記的單頁(yè)應(yīng)用的文章。 鑒于該篇文章閱讀量大,回復(fù)的同學(xué)也挺多的,特地抽空寫(xiě)了一篇 vue2.0 下的 vuex 使用方法,傳送門(mén):使用 Vuex + Vue.js 構(gòu)建單頁(yè)應(yīng)用【新篇】 ---------...
閱讀 858·2021-10-25 09:48
閱讀 621·2021-08-23 09:45
閱讀 2511·2019-08-30 15:53
閱讀 1766·2019-08-30 12:45
閱讀 618·2019-08-29 17:21
閱讀 3429·2019-08-27 10:56
閱讀 2560·2019-08-26 13:48
閱讀 705·2019-08-26 12:24