天天看點

Vue.js 系列教程 4:Vuex

原文:intro-to-vue-4-vuex

譯者:nzbin

這是關于 JavaScript 架構 Vue.js 五個教程的第四部分。在這一部分,我們會學習使用 Vuex 進行狀态管理。這個系列教程并不是一個完整的使用者手冊,而是通過基礎知識讓你快速了解 Vuejs 以及它的用途。

Vue.js 系列教程 4:Vuex

系列文章:

  1. 渲染, 指令, 事件
  2. 元件, Props, Slots
  3. Vue-cli
  4. Vuex (你在這!)
  5. Animations

Vuex

如果你錯過了關于元件及 Vue-cli 的部分,在閱讀本篇文章之前應該先讀讀這幾部分。現在我們已經了解了關于元件、傳遞狀态和 props 的基本知識,接下來讨論一下 Vuex,它是狀态管理的好工具。

之前,我們是從頂層元件向下傳遞狀态,而同胞元件之間并沒有分享資料。如果它們需要互相通信,我們要在應用程式中推送狀态。這是可以的!但是一旦你的程式變得複雜,這種方法就沒有意義了。如果你之前用過 Redux,那 Vuex 中所有的概念及實作對你也不陌生。Vuex 是 Vue 中的 Redux。實際上,Redux 也可以用于 Vue,但是,使用專門為 Vue 設計的工具 Vuex 更加有利。

首先,安裝 Vuex:

npm install vuex

或者

yarn add vuex

我這樣設定: 在 `/src` 目錄下,我建立了名為 store 的目錄 ( 這是一種選擇,你也可以在同級目錄建立一個 `store.js` 檔案 ),再在其中建立一個名為 `store.js`的檔案。`store.js` 中的初始設定如下 ( vstore sublime snippet ):

import Vue from 'vue';     import Vuex from 'vuex';     Vue.use(Vuex);     export const store = new Vuex.Store({       state: {         key: value       }     });      

key: value

是狀态資料的占位符。在其他例子中,我們已經使用

counter: 0

在 `main.js` 檔案中,我們将執行以下更新(加粗顯示更新的行):

import Vue from 'vue';     import App from './App.vue';     import { store } from './store/store';     new Vue({       el: '#app',       store: store,       template: '<App/>',       components: { App }     });      

更新之後,和之前做的元件一樣,我們可以把

data()

作為狀态,然後我們通過以下三種方式使用或者更新狀态:

  • Getters 可以在模闆中靜态的顯示資料。換句話說,getters 可以讀取資料,但不能改變狀态。
  • Mutations 允許更新狀态,但永遠是同步的。Mutations 是 store 中改變狀态資料的唯一方式。
  • Actions 允許異步更新狀态,但是需要使用一個已經存在的 mutation 。如果你需要以特定的順序同時執行不同的 mutations 會非常有用。

如果你以前沒有接觸過,也許很難了解為什麼會使用異步狀态的變化,是以先看看理論上它會發生什麼,然後再開始下一部分。假如你運作 Tumblr。如果頁面中有大量長時間運作的 gif 圖檔。你隻想每次載入其中一部分,比如當使用者将頁面滾動到底部 200px 時,加載 20 個圖檔。

你需要使用 mutation 展示後面的 20 個。但是現在還沒有後面的 20 個,你不知道何時到達頁面底部。是以,在程式中,建立一個事件來監聽滾動的位置然後觸發相應的操作。

然後,該操作将從資料庫中檢索後面 20 個圖像的 URL,并将 20 個圖檔的狀态添加到 mutation 中然後顯示。

本質上,Actions 建立一個請求資料的架構。它們使用一緻的方法來應用異步方式中的資料。

最基本的抽象例子

在下面的例子中,展示了每個屬性最基本的實作方式,是以你可以了解如何設定及使用。載荷是可選參數,可以通過它定義正在更新的元件的數值。不用擔心,我們随後将示範一個實際案例,現在最重要的是了解基本概念。

`store.js`:

export const store = new Vuex.Store({       state: {         counter: 0       },       // 展示内容, 無法改變狀态       getters: {         tripleCounter: state => {           return state.counter * 3;         }       },       // 改變狀态       //mutations 永遠是同步的       mutations: {         // 顯示傳遞的載荷 payload, 用 num 表示         increment: (state, num) => {           state.counter += num;         }       },        // 送出 mutation, 這是異步的       actions: {         // 顯示傳遞的載荷 payload, 用 asynchNum ( 一個對象 )表示         asyncDecrement: ({ commit }, asyncNum) => {           setTimeout(() => {             // asyncNum 對象可以是靜态值             commit('decrement', asyncNum.by);           }, asyncNum.duration);         }       }     });      

一個很好的功能是我們可以在 mutations 中傳回整個狀态對象,但是不必這樣做,我們隻使用我們需要的。時間穿梭測試(進入 mutations 中尋找錯誤)仍然可以工作。

在元件中,我們将對 getters 使用

computed

(這很重要,因為 value 值已經計算好了),在

methods

中使用

dispatch

來通路 mutations 和 actions:

`app.vue`:

computed: {       value() {         return this.$store.getters.value;       }     },     methods: {       increment() {         this.$store.dispatch('increment', 2)       }     }      

或者,您可以使用擴充運算符。我發現如果需要大量 mutations/actions 的時候是非常有用的:

export default {       // ...       methods: {         ...mapActions([           'increment', // 将 this.increment() 映射到 this.$store.commit('increment')           'decrement',           'asyncIncrement'         ])       }     }      

簡單的執行個體

讓我們再看一看天氣通知的程式, 在它的 Vuex store 中有少量且簡單的狀态。這是示例代碼的倉庫.

See the Pen Vue Weather Notifier by Sarah Drasner (@sdras) on CodePen.

`store.js`:

import Vue from 'vue';     import Vuex from 'vuex';     Vue.use(Vuex);     export const store = new Vuex.Store({       state: {         showWeather: false,         template: 0       },         mutations: {           toggle: state => state.showWeather = !state.showWeather,           updateTemplate: (state) => {             state.showWeather = !state.showWeather;             state.template = (state.template + 1) % 4;           }       }     });      

我們在這裡設定了

showWeather

的狀态,它的初始值為 false ,因為我們不希望任何動畫立即執行,隻有當使用者點選按鈕時才會執行。在 mutations 中,我們可以切換

showWeather

的狀态。

我們也将狀态中的

template

設定為 0 。我們會在每個天氣元件中循環使用這個數字。是以在 mutations 中,我們建立了一個名為

updateTemplate

的方法。它會同時切換

showWeather

的狀态并且更新

template

加 1 後的數值,但是值為 4 時再點選會變成 0 。

App.vue:

<template>       <div id="app">         ...         <g id="phonebutton" @click="updateTemplate" v-if="!showWeather">            ...         </g>         <transition              @leave="leaveDroparea"             :css="false">           <g v-if="showWeather">             <app-droparea v-if="template === 1"></app-droparea>             <app-windarea v-else-if="template === 2"></app-windarea>             <app-rainbowarea v-else-if="template === 3"></app-rainbowarea>             <app-tornadoarea v-else></app-tornadoarea>           </g>         </transition>         ...       </div>     </template>      
<script>       import Dialog from './components/Dialog.vue';       ...       export default {         computed: {           showWeather() {             return this.$store.state.showWeather;           },           template() {             return this.$store.state.template;           }         },         methods: {           updateTemplate() {             this.$store.commit('updateTemplate');           }         },         ...         components: {           appDialog: Dialog,           ...         }     }     </script>      

`dialog.vue`:

<script>     export default {       computed: {         template() {           return this.$store.state.template;         }       },       methods: {         toggle() {           this.$store.commit('toggle');         }       },       mounted () {           //enter weather           const tl = new TimelineMax();         ...       }     }     </script>      

在上面的代碼中,App 元件使用了

showWeather

依次展示模闆, 而 Dialog 元件隻切換元件的可見性。在 App.vue 中,我們根據 App

<template>

中的模闆數值,通過第一章學過的的條件渲染來展示以及隐藏不同的子元件。在 App 中, 我們通過

computed

數值監聽 store 中狀态的變化,使用 methods 中的

toggle()

updateTemplate()

送出 store 的 mutations 。

這是一個基本示例,但是你可以了解如何處理有大量狀态的複雜程式,這有利于在在一個地方管理所有的狀态,而不是上下移動元件。尤其當同胞元件之間通信的時候。

如果你想深入了解 Vuex , 可以看這篇 文檔 。你肯能注意到我們在最後一個例子中使用了

<transition>

元件,還有大量動畫。我們會在下一部分展開讨論。

感謝您的閱讀,如果您對我的文章感興趣,可以關注我的部落格,我是叙帝利,下篇文章再見!

開發低代碼平台的必備拖拽庫 https://github.com/ng-dnd/ng-dnd

基于 Angular Material 的中背景管理架構 https://github.com/ng-matero/ng-matero

Angular Material Extensions 擴充元件庫 https://github.com/ng-matero/extensions

仿 Windows 照片檢視器插件 https://github.com/nzbin/photoviewer

仿 Windows 照片檢視器插件 jQuery 版 https://github.com/nzbin/magnify

完美替代 jQuery 的子產品化 DOM 庫 https://github.com/nzbin/domq

簡化類名的輕量級 CSS 架構 https://github.com/nzbin/snack

與任意 UI 架構搭配使用的通用輔助類 https://github.com/nzbin/snack-helper

單元素純 CSS 加載動畫 https://github.com/nzbin/three-dots

有趣的 jQuery 卡片抽獎插件 https://github.com/nzbin/CardShow

懸疑科幻電影推薦 https://github.com/nzbin/movie-gallery

鍛煉記憶力的小程式 https://github.com/nzbin/memory-stake