1. 程式人生 > >九. Vuex詳解

九. Vuex詳解

#### 1. 理解Vuex ##### 1.1 Vuex功能 **官方解釋** Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用 集中式儲存 管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也整合到 Vue 的官方除錯工具 `devtools extension`,提供了諸如零配置的 `time-travel` 除錯、狀態快照匯入匯出等高階除錯功能。 **狀態管理到底是什麼?** 狀態管理模式、集中式儲存管理這些名詞聽起來就非常高大上,讓人捉摸不透。其實你可以簡單的將其看成把需要多個元件共享的變數全部儲存在一個物件裡面。然後將這個物件放在頂層的Vue例項中讓其他元件可以使用。那麼多個元件是不是就可以共享這個物件中的所有變數屬性了呢?是的 如果是這樣的話為什麼官方還要專門出一個外掛Vuex呢?難道我們不能自己封裝一個物件來管理嗎?當然可以,只是我們要先想想VueJS帶給我們最大的便利是什麼呢?沒錯,就是響應式。如果你自己封裝實現一個物件能不能保證它裡面所有的屬性做到響應式呢?當然也可以,只是自己封裝可能稍微麻煩一些。不用懷疑,Vuex就是為了提供這樣一個在多個元件間共享狀態的外掛,用它就可以了。 **管理什麼狀態?** 但是有什麼狀態是需要我們在多個元件間共享的呢?如果你做過大型開放一定遇到過多個狀態在多個介面間的共享問題。比如使用者的登入狀態、使用者名稱稱、頭像、地理位置資訊等。比如商品的收藏、購物車中的物品等。這些狀態資訊都可以放在統一的地方對它進行儲存和管理,而且它們還是響應式的。 OK,從理論上理解了狀態管理之後,讓我們從實際的程式碼再來看看狀態管理。 ##### 1.2 單介面的狀態管理 **理解** 我們知道,要在單個元件中進行狀態管理是一件非常簡單的事情。 什麼意思呢?我們來看下面的圖片。這圖片中的三種東西,怎麼理解呢? - State:不用多說,就是我們的狀態。(你姑且可以當做就是data中的屬性) - View:檢視層,可以針對State的變化,顯示不同的資訊。(這個好理解) - Actions:這裡的Actions主要是使用者的各種操作:點選、輸入等會導致狀態的改變。 **實現** 在下面案例中,我們有木有狀態需要管理呢?沒錯就是counter。counter需要某種方式被記錄下來,也就是我們的State。counter目前的值需要被顯示在介面中,也就是我們的View部分。 介面發生某些操作時(我們這裡是使用者的點選,也可以是使用者的input),需要去更新狀態,也就是我們的Actions,這不就是上面的流程圖了嗎? ```html ``` ##### 1.3 多介面狀態管理 Vue已經幫我們做好了單個介面的狀態管理,但是如果是多個介面呢? - 多個檢視都依賴同一個狀態(一個狀態改了,多個介面需要進行更新) - 不同介面的Actions都想修改同一個狀態(Home.vue需要修改,Profile.vue也需要修改這個狀態) 也就是說對於某些狀態(狀態1/狀態2/狀態3)來說只屬於我們某一個試圖,但是也有一些狀態(狀態a/狀態b/狀態c)屬於多個試圖共同想要維護的。 - 狀態1/狀態2/狀態3你放在自己的房間中,你自己管理自己用沒問題。 - 但是狀態a/狀態b/狀態c我們希望交給一個大管家來統一幫助我們管理! - 沒錯,Vuex就是為我們提供這個大管家的工具。 全域性單例模式(大管家) - 我們現在要做的就是將共享的狀態抽取出來,交給我們的大管家統一進行管理。 - 之後每個試圖按照大管家規定好的規定,進行訪問和修改等操作。這就是Vuex背後的基本思想。 ##### 1.4 Vuex狀態管理圖例
#### 2. Vuex基本使用 ##### 2.1 安裝Vuex ```javascript npm install vuex --save ``` ##### 2.2 簡單的案例 使用Vuex實現一下之前的計數器案例 **store/index.js** ```javascript import VueX from 'vuex' import Vue from 'vue' Vue.use(VueX) const store = new VueX.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } } }) export default store ``` **將store掛載到Vue例項中** 我們讓所有的Vue元件都可以使用這個store物件,來到main.js檔案匯入store物件,並且放在new Vue中。這樣在其他Vue元件中,我們就可以通過this.$store的方式獲取到這個store物件了。 ```javascript //... import store from '@/store' //... new Vue({ store, render: h =>
h(App), }).$mount('#app') ``` **元件中使用Vuex的count** ```html ``` 好的,上面就是使用Vuex最簡單的方式了。 我們來對使用步驟,做一個簡單的總結: - 提取出一個公共的store物件,用於儲存在多個元件中共享的狀態。 - 將store物件放置在`new Vue`物件中,這樣可以保證在所有的元件中都可以使用到。 - 在其他元件中使用store物件中儲存的狀態即可 - 通過`this.$store.state`屬性的方式來訪問狀態 - 通過`this.$store.commit('mutation中的方法')`來修改狀態 >
注意: > ① 我們通過提交mutation的方式,而非直接改變store.state.count > ② 這是因為Vuex可以更明確的追蹤狀態的變化,所以不要直接改變store.state.count的值。 ##### 2.3 Vux的幾個核心概念 我們來對這幾個概念一一理解 - State - Getters - Mutation - Action - Module #### 3. State **State單一狀態樹** Vuex提出使用單一狀態樹, 什麼是單一狀態樹呢?英文名稱是Single Source of Truth,也可以翻譯成單一資料來源。 但是它是什麼呢?我們來看一個生活中的例子。我們知道在國內我們有很多的資訊需要被記錄,比如上學時的個人檔案,工作後的社保記錄,公積金記錄,結婚後的婚姻資訊,以及其他相關的戶口、醫療、文憑、房產記錄等等(還有很多資訊)。這些資訊被分散在很多地方進行管理,有一天你需要辦某個業務時(比如入戶某個城市),你會發現你需要到各個對應的工作地點去列印、蓋章各種資料資訊,最後到一個地方提交證明你的資訊無誤。這種儲存資訊的方案不僅僅低效而且不方便管理,以及日後的維護也是一個龐大的工作(需要大量的各個部門的人力來維護,當然國家目前已經在完善我們的這個系統了)。 這個和我們在應用開發中比較類似:如果你的狀態資訊是儲存到多個Store物件中的,那麼之後的管理和維護等等都會變得特別困難。所以Vuex也使用了單一狀態樹來管理應用層級的全部狀態。單一狀態樹能夠讓我們最直接的方式找到某個狀態的片段,而且在之後的維護和除錯過程中也可以非常方便的管理和維護。 #### 4. Getters > 類似於元件中的計算屬性computed 有時候我們需要從store中獲取一些state變化後的狀態,比如下面的Store中獲取學生年齡大於20的學生個數。 ```javascript state: { students: [ {id: 110, name: 'polaris',age: 18}, {id: 111, name: 'rose',age: 22}, {id: 112, name: 'jack',age: 34}, {id: 113, name: 'tom',age: 11}, ] }, ``` 我們可以在Store中定義getters ```javascript getters: { greateAgesCount: state => { return state.students.filter(s => s.age >= 20).length; } } //如果我們已經有了一個獲取所有年齡大於20歲學生列表的getters, 那麼程式碼也可以這樣來寫 getters: { greateAgesStudents: state => { return state.students.filter(s => s.age >= 20); }, greateAgesCount: (state, getters) => { return getters.greateAgesStudents.length; } } ``` ```javascript //元件中獲取getters計算後的值 computed: { greateAgesCount() { return this.$store.getters.greateAgesCount } }, ``` getters預設是不能傳遞引數的,如果希望傳遞引數,那麼只能讓getters本身返回另一個函式。比如上面的案例中我們希望根據ID獲取使用者的資訊。 ```javascript getters: { studentById: state => { return id => { return state.students.find(s => s.id === id) } } } ``` ```javascript computed: { studentById() { return this.$store.getters.studentById(112) } } ``` #### 5. Mutation ##### 5.1 狀態更新 Vuex的store狀態的更新唯一方式:**提交Mutation** Mutation主要包括兩部分: - 字串的 **事件型別**`type` - 一個 **回撥函式** `handler`,該回調函式的第一個引數就是state。 mutation的定義方式: ```javascript //如下:increment就是事件型別,(state) {state.count++;}是回撥函式 mutations: { increment(state) { state.count++; }, decrement(state) { state.count--; } } ``` 在某個元件中通過mutation更新state值 ```javascript increment: function() { this.$store.commit('increment'); } ``` ##### 5.2 傳遞引數 在通過mutation更新資料的時候,有可能我們希望攜帶一些 **額外的引數**,引數被稱為是mutation的`載荷(Payload)` Mutation中的程式碼: ```javascript mutations: { increment(state,n) { state.count += n; }, decrement(state,n) { state.count -= n; } } ``` 在某個元件中通過mutation更新state值 ```javascript methods: { increment() { this.$store.commit('increment',2) }, decrement() { this.$store.commit('decrement',2) } } ``` 但是如果引數不是一個呢?比如我們有很多引數需要傳遞,這個時候我們通常會以物件的形式傳遞,也就是payload是一個物件。 ```javascript changeCount(state,payload) { state.count = payload.count } ``` ```javascript changeCount() { this.$store.commit('changeCount',{count: 5}) } ``` ##### 5.3 提交風格 上面的通過commit進行提交是一種普通的方式 Vue還提供了另外一種風格, 它是一個包含type屬性的物件 ```javascript changeCount() { this.$store.commit({ type: 'changeCount', count: 100 }) } ``` Mutation中的處理方式是將整個commit的物件作為payload使用, 所以程式碼沒有改變依然如下: ```javascript changeCount(state,payload) { state.count = payload.count } ``` ##### 5.4 響應規則 Vuex的store中的state是響應式的,當state中的資料發生改變時Vue元件會自動更新。 這就要求我們必須遵守一些Vuex對應的規則 - 提前在store中初始化好所需的屬性 - 當給state中的物件新增新屬性時,,使用下面的方式 - 方式一:使用`Vue.set(obj, 'newProp', 123)` - 方式二:用新物件給舊物件重新賦值 **state中的物件新增新屬性的案例** 我們來看一個例子:當我們點選更新資訊時介面並沒有發生對應改變,如何才能讓它改變呢? ```javascript import VueX from 'vuex' import Vue from 'vue' Vue.use(VueX) const store = new VueX.Store({ state: { info: { name: 'polaris', age: 18 } }, mutations: { updateInfo(state,payload) { state.info['height'] = payload.height } } }) export default store ``` ```html ``` 下面程式碼的方式一和方式二,都可以讓state中的屬性是響應式的 ```javascript mutations: { // updateInfo(state,payload) { // state.info['height'] = payload.height // } updateInfo(state, payload) { //方式一 // Vue.set(state.info,'height',payload.height) //方式二 state.info = {...state.info, 'height': payload.height} } } ``` > 我們也可以響應式的刪除某個物件的屬性如:`Vue.delete(state.info,'height')` ##### 5.5 常量型別 **概念** 我們來考慮一個問題,在mutation中我們定義了很多事件型別(也就是其中的方法名稱)。當我們的專案增大時Vuex管理的狀態越來越多,需要更新狀態的情況越來越多,那麼意味著Mutation中的方法越來越多。方法過多使用者需要花費大量的經歷去記住這些方法甚至是多個檔案間來回切換檢視方法名稱,甚至如果不是複製可能還會出現寫錯的情況。 如何避免上述的問題呢?在各種Flux實現中,一種很常見的方案就是 使用常量替代Mutation事件的型別 。我們可以將這些常量放在一個單獨的檔案中方便管理以及讓整個app所有的事件型別一目瞭然。 具體怎麼做呢?我們可以建立一個檔案 `mutation-types.js`, 並且在其中定義我們的常量。 定義常量時我們可以使用ES2015中的風格,使用一個常量來作為函式的名稱。 **程式碼** ##### 5.6 同步函式 通常情況下Vuex要求我們Mutation中的方法必須是同步方法。 主要的原因是當我們使用devtools時,利用devtools幫助我們捕捉mutation的快照,但是如果是非同步操作那麼devtools將不能很好的追蹤這個操作什麼時候會被完成。即如果Vuex中的程式碼我們使用了非同步函式,你會發現state中的info資料一直沒有被改變因為它無法追蹤到。所以通常情況下不要在mutation中進行非同步的操作。 ```javascript mutations: { updateInfo(state) { setTimeout(() => { state.info.name = "GG"; },1000) } }, ``` #### 6. Action ##### 6.1 基本定義 前面我們強調不要再Mutation中進行非同步操作,但是某些情況我們確實希望在Vuex中進行一些非同步操作,比如網路請求必然是非同步的,這個時候怎麼處理呢? Action類似於Mutation,但是是用來代替Mutation進行非同步操作的。 Action的基本使用程式碼如下 ```javascript mutations: { updateInfo(state) { // setTimeout(() => { // state.info.name = "GG"; // },1000) state.info.name = "GG"; } }, actions: { actUpdateInfo(context) { setTimeout(() => { context.commit('updateInfo'); },1000) } } ``` context是什麼?context是和store物件具有相同方法和屬性的物件,也就是說我們可以通過context去進行commit相關的操作,也可以獲取context.state等。但是注意這裡它們並不是同一個物件,為什麼呢? 我們後面學習Modules的時候再具體說。 這樣的程式碼是否多此一舉呢?我們定義了actions,然後又在actions中去進行commit,這不是脫褲放屁嗎?事實上並不是這樣,如果在Vuex中有非同步操作那麼我們就可以在actions中完成了。 ##### 6.2 分發 在Vue元件中, 如果我們呼叫action中的方法,那麼就需要使用dispatch,同樣的dispatch也是支援傳遞payload ```javascript methods: { updateInfo() { // this.$store.commit('updateInfo'); this.$store.dispatch('actUpdateInfo'); } } ``` ##### 6.3 物件的解構寫法 ```javascript const obj = { name: 'why', age: 18, height: 1.88 }; //順序可變 const {age, name, height} = obj; console.log(name); ``` **在Actions中使用物件的解構寫法** > getters 和 mutations 當然也可以使用物件的解構寫法 ```javascript actions: { actUpdateInfo({commit}) { setTimeout(() => { commit('updateInfo'); },1000) } } ``` ##### 6.4 Action返回的Promise > 不清楚promise的用法請回看第八章 **引入** 當我們的store中非同步操作執行結束後,是否能夠提醒一下呼叫者已經成功執行了呢? 我們可以這樣實現: ```javascript actions: { actUpdateInfo(context,success) { setTimeout(() => { context.commit('updateInfo'); success(); },1000) } }, ``` ```javascript methods: { updateInfo() { this.$store.dispatch('actUpdateInfo',() => { console.log('執行成功!'); }); } } ``` 但是這樣就不能傳入其他引數了,那我們再換種寫法! ```javascript actions: { actUpdateInfo(context,payload) { setTimeout(() => { context.commit('updateInfo',payload.message); console.log(payload.message); payload.success(); },1000) } }, ``` ```javascript methods: { updateInfo() { this.$store.dispatch('actUpdateInfo', { message: '我是攜帶的引數', success: () => { console.log('執行成功!'); } }); } } ``` 雖然可以實現,但是回撥的資訊和攜帶的引數寫到一起去了,這種做法是不夠優雅的,下面我們通過Promise實現! **使用Promise** 前面我們學習ES6語法的時候說過Promise經常用於非同步操作。在Action中我們可以將非同步操作放在一個Promise中,並且在成功或者失敗後呼叫對應的resolve或reject。 ```javascript actions: { actUpdateInfo(context, payload) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updateInfo'); console.log(payload); resolve('執行成功!'); }, 1000) }) } }, ``` ```javascript methods: { updateInfo() { this.$store.dispatch("actUpdateInfo", '我是攜帶的資訊').then(res => { console.log(res); }); }, }, ``` #### 7. Module ##### 7.1 理解 Module是模組的意思,為什麼在Vuex中我們要使用模組呢? Vue使用單一狀態樹,那麼也意味著很多狀態都會交給Vuex來管理。當應用變得非常複雜時store物件就有可能變得相當臃腫。為了解決這個問題Vuex允許我們將store分割成模組(Module),而每個模組擁有自己的state,mutations,actions,getters等。 我們按照什麼樣的方式來組織模組呢?看下面程式碼 ```javascript //注意:模組中mutation和getters接收的第一個引數state,context是區域性狀態物件。 const moduleA = { state: { name: 'polaris' }, mutations: { updateName(state) { state.name = 'GG'; } }, actions: { actUpdateName(context) { setTimeout(() => { context.commit('updateName') },1000) } }, getters: { fullName(state) { return state.name + "hahaha"; } } } const moduleB = { state: { name: 'rose' }, mutations: {}, actions: {}, getters: {} } const store = new Vuex.store({ modules: { a: moduleA, b: moduleB } }) ``` ```javascript //state,呼叫時必須加上模組名,不同模組間可以有相同的值 this.$store.state.a.name //獲取moduleA的狀態中的值 this.$store.state.b.name //獲取moduleB的狀態中的值 //mutations,不同模組間可以有相同的值但是不要這麼寫,因為外部會同時呼叫不同模組的mutations方法 updateName() { this.$store.commit('updateName'); //依次去模組中找 } //getters,不同模組間不能有相同的值,會報錯 this.$store.getters.fullName //依次去模組中找 //actions,不同模組有相同的mutations方法時,會同時呼叫不同模組的mutations方法 actUpdateName() { this.$store.dispatch('actUpdateName') } //=> 總結:除了state,各個模組中的其他內容不要重名! ``` ##### 7.2 store推薦的專案結構

相關推薦

. Vuex

#### 1. 理解Vuex ##### 1.1 Vuex功能 **官方解釋** Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用 集中式儲存 管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也整合到 Vue 的官方除錯工具 `devtools

Vuex

可維護 語法 接收數據 大量 流程圖 fault 基礎 單獨 裏的 為什麽要單獨增加Vuex? 因為Vuex裏面涉及很多概念性的東西,一時之間弄不懂,當時我在項目中集成Vuex時查了很多資料,踩了不少的坑。如果剛開始接觸Vuex,你肯定會從官方文檔看起,官方給的例子,就是

2018年藍橋杯B組c/c++ 第

標題:全球變暖 你有一張某海域NxN畫素的照片,".“表示海洋、”#"表示陸地,如下所示: ....... .##.... .##.... ....##. ..####. ...###. ....... 其中"上下左右"四個方向上連在一起的一片陸地組成一座島嶼。例如上圖就有2座

併發系列()-----AQS共享模式的資源獲取與釋放

一 簡介     到目前為止已經知道了AQS中同步佇列的基本的工作原理可以總結為維護同步佇列,獲取資源和改變執行緒狀態。上一篇文章中主要總結了獨佔模式下的資源獲取。這篇主要總結一下AQS中的共享模式。    共享模式從字面上理解就是,這個資源可以被

java提高篇()-----匿名內部類

       在java提高篇-----詳解內部類中對匿名內部類做了一個簡單的介紹,但是內部類還存在很多其他細節問題,所以就衍生出這篇部落格。在這篇部落格中你可以瞭解到匿名內部類的使用、匿名內部類要注

vue--vuex

  Vuex     什麼是Vuex?        官方說法:Vuex 是一個專為 Vue.js應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。       個人理解:Vuex是用來管理元件之間通訊的一個外掛     為什麼要用Vuex

微信小程序開發教程()視圖層——.wxss

hone mnt 而且 padding 移動 圖層 組成 特性 -1   WXSS是一套樣式語言,用於描述WXML的組件樣式。   官方文檔表示,WXSS的選擇器目前支持(“.class”、“#id”、“elemnt”、“element,element”、“::after”

MySQL()之數據表的查詢(SELECT語法)二

clas reg 3.2 查詢語句 我們 lin where 過濾 情況 上一篇講了比較簡單的單表查詢以及MySQL的組函數,這一篇給大家分享一點比較難得知識了,關於多表查詢,子查詢,左連接,外連接等等。希望大家能都得到幫助! 在開始之前因為要多表查詢,所以搭建好環境:

vuex基礎及項目實例

export DDU 整合 輸入 發的 .com return isp 分享 1、概念 Vuex 是一個專為 Vue.js 的SPA單頁組件化應用程序開發的狀態管理模式插件,它包括State(數據源)、Getters(計算屬性)、Modules(模塊)、Mutation

jsp 大內置對象和其作用

tex next 應用服務 java 響應 exceptio servle 輸出流 XML JSP中一共預先定義了9個這樣的對象,分別為:request、response、session、application、out、pagecontext、config、page、exc

從零開始的linux 第十章(mv命令)

mv移動文件從零開始的linux 第十九章hello~~又到了一周一更新博客的時候啦~~這周51CTO成功將博客功能升級~~給我們帶來了全新的體驗~全新的界面~全新的視感~~不過,在編輯器上~小編還是習慣用原來的編輯器,感謝工作人員在內測時候廣泛采納用戶的建議~對博客進行一次又一次的修改,嗯,最辛苦的還是我們

Android項目實戰(三十):Android集成Unity3D項目(圖文

jar包沖突 scree pmap module 項目實戰 技術 詳細 應用端 原來 原文:Android項目實戰(三十九):Android集成Unity3D項目(圖文詳解)  需求:   Unity3D 一般用於做遊戲 而且是跨平臺的。原本設計是Android 應用端A

機器學習中的概率模型和概率密度估計方法及VAE生成式模型(第5章 總結)

ces mark TP 生成 機器 分享 png ffffff images ? ?機器學習中的概率模型和概率密度估計方法及VAE生成式模型詳解之九(第5章 總結)

Zookeeper):Zookeeper高可用方面的建議和日常運維

劃算 建議 都是 日常 網絡 ont 需要 sof 可用 集群數量:3、5、7這樣的奇數。當然偶數也可以組成集群只是3臺與4臺組成的集群其實允許的故障數量是一樣的,所以4臺組成的集群不劃算。多機房問題:如果每個機房之間的網絡狀況良好可以在每個機房都部署ZK服務器來組成一個大

(第篇)Iptables

練習 etc 條目 root 第九篇 包括 路由選擇 網絡掃描 轉發 常見的網絡攻擊形式 1.拒絕服務攻擊:DOS 2.分布式拒絕服務攻擊 DDOS 3.漏洞入侵 4.口令猜測 以上內容簡單了解,具體可自行百度,此處不必知曉。 Linux防火墻基礎 Linux防火墻體系主要

Flutter 布局()- Flow、Table、Wrap

bool shade orm src html break display tom empty 本文主要介紹Flutter布局中的Flow、Table、Wrap控件,詳細介紹了其布局行為以及使用場景,並對源碼進行了分析。 1. Flow A widget that i

[]基礎數據類型之Boolean

全部 hashcode 詳解 兩種 class -c lean title 14. 相對於其他的基礎性 類型Boolean是很簡單的 Boolean 基本數據類型boolean 的包裝類 Boolean 類型的對象包含一個 boolean 類型的字段

Oracle 12c項數據庫對象管理操作

查看家目錄 緩存 函數索引 clu 磁盤 linux creat onu true 簡介 1.用戶管理2.用戶授權3.事務管理4.索引5.視圖以及物化視圖6.序列7.導入導出數據8.同義詞9.分區表 實驗環境 系統環境:centos7.4Oracle服務IP地址:192

課--09_01_磁盤及文件系統管理之三

lock 多系統 otl rtx 塊大小 ble 當前 part 文件 一、VFS (Virtual File System)1: 用戶模式--用戶空間--用戶進程進程以模式的形式運行在的空間--用戶空間2:內核模式--內核空間3:block size : 1024-1k,

課-09_02_磁盤及文件系統管理之五

大小 卷標 設備 空間 part 系統管 支持 -m nod 一。創建文件系統---格式化分區就是創建文件系統 mkfs make file system---創建文件系統的命令mkfs -t FSTYPE PARTmkfs -t ext2 /dev/sda4---