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