Vuex2 實戰

圖片描述

本文就着以前幾天的文章 Vue2 移動端開發環境搭建 繼續擴展,上一篇文章有人反饋說講到最後只有 rem 是移動端相關的知識,沒錯我我的認爲除了 remtouch 事件特殊外其它與 pc 端無異(手機系統版本和瀏覽器的 bug 放在這裏討論無心義),下面請出今天的大咖 vuexcss

狀態管理工具

說到這裏有兩個疑:html

1.什麼是狀態管理工具?vue

狀態管理工具起源於早期的 Flux,意在管理項目中各個狀態,狀態保存在 store 中,狀態是隻讀的,只能經過 action 觸發 store 的更新。react

2.問咱們爲何使用狀態管理工具?android

當一個項目逐漸壯大咱們須要管理的狀態就會變得繁雜,例如:父級組件傳遞狀態到子組件,子組件再次改變同一個狀態時就要想辦法告訴父級組件狀態改變了,狀況再複雜點呢!子組件之間又相互影響,又影響到其餘子組件的父組件呢?狀況變得愈來愈糟糕,咱們須要一個全局的公共狀態管理容器,把咱們的狀態都放進去統一管理。ios

大型項目對狀態的管理需求越來約大,從而發展到今天的 react + redux 組合,angular + ngRedux 組合, vue + vuex 組合。git

這裏 redux 做爲後起之秀有不少真對 Flux 的改進。感興趣的能夠深刻了解,這裏只關心 vuex 並且是 2.x,用過 1.x 版本的能夠順利過渡到 2.x。github

Vuex2 概覽

Vuex2 官方文檔: http://vuex.vuejs.org/en/inde...

能看懂文檔的能夠跳過實戰了。。。web

實戰開始以前先放出文檔,歸根結底仍是由於文檔描述過於簡單(簡陋),看的我雲裏霧裏,這個對於搞過 redux 的我而言不是原理不理解,而是用法上沒有一個能讓我一眼看懂的簡單粗暴的例子。vuex

方便你們理解工做流程,先給出官方的配圖

圖片描述

從左邊看 vue components(組件) -> action(只能經過 dispatch 調用,與此同時能夠異步與後端的 API 作交互) -> mutations(只能經過 action 發起 commit 調用,此時開發工具能夠監測到數據的流動) -> state (mutations 傳遞修改過的狀態到 state)-> state 自動同步到視圖

完成整個循環數據的流動是單向的,從而避免了雙向數據流動的複雜性,不一樣的組件能夠修改同一個狀態,並將修改後的狀態同步到全部關聯此狀態的組件。

實戰

原理就解釋到這,直接上一個實際例子。

這個例子的背景是我須要一個 webview,說到這不得不提 android 和 ios 的區別,目的就是全局判斷設備類型存入 state 在局部直接取到類型作判斷。

這裏其實能夠經過 props 傳遞 data 實現,說到這裏考慮到可能產生多級子組件,我每一層都須要 props 傳遞,又顧及到是全局屬性(由於嵌入到哪一個平臺的頁面就走那個平臺的接口)

安裝 vuex 的步驟就省了,在以前的文章介紹過了

在 src 下新建文件夾 vuex,進入 vuex 新建 store.js

而後去 main.js 加入

import store from './vuex/store'

再修改 Vue 實例以下

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

咱們去新建的 store.js

import Vue  from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    platform: ''
  },
  mutations: {
    SET_APP(state, platform) {
      state.platform = platform;
    }
  },
  actions: {
    setApp({commit}, platform) {
      commit('SET_APP', platform);
    }
  },
  getters: {
    getApp: (state) => state.platform
  }
})
看到這裏不急着往下進行,官方給的建議是 state、mutations、actions、getters 都分離成單獨文件再引入到 store.js 中,這裏只是爲了提供一個簡單粗暴的例子,把大部分流程都封裝在一個文件裏了,也方便修改測試。跟着上面工做流程圖一步一步的走一遍,不難發現咱們整個流程走下來只差組件分別調用 setApp 和 getApp 了。

說到組件先來看看完整的 App.vue

<template>
  <div id="app">
    <div class="logo">
      <img src="./assets/logo.png">
    </div>
    <article-content></article-content>
    <share></share>
    <comment></comment>
  </div>
</template>

<script>
import comment from './component/Comment.vue';
import articleContent from './component/ArticleContent.vue';
import share from './component/Share.vue';

export default {
  data () {
    return {
    }
  },
  components: {
    articleContent,
    comment,
    share
  },
  mounted () {
    let u = navigator.userAgent;

    if ( u.indexOf('Android') > -1 || u.indexOf('Adr') > -1 ) {
      this.$store.dispatch('setApp', 'android');
    } else if ( !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) ) {
      this.$store.dispatch('setApp', 'ios');
    }
  }
}
</script>

<style lang="sass">
  @import "/style/base.scss";
</style>

這裏引入了三個組件,在 mounted() 裏咱們判斷設備類型併發起 dispatch ,關鍵方法是 this.$store.dispatch('setApp', ...args);

簡單易懂咱們 dispatch 了一個 action(setApp),而後 commit 到 mutations(SET_APP),在 SET_APP 中修改了 state.platform

下面看看子組件是怎麼獲取,由於都是重複的用法因此只給一個 share 組件

<template>
  <div class="article-share-block">
    <div class="divider-line" layout="row" layout-align="center center">
      <div class="left-line" flex></div>
      <p class="label">分享到</p>
      <div class="right-line" flex></div>
    </div>
    <div layout="row" layout-align="space-between center">
      <img class="share-icon" v-tap="{ methods: share, target: 'wechatTimeline' }" src="../img/wechat_timeline.png" alt="">
      <img class="share-icon" v-tap="{ methods: share, target: 'wechatFriend' }" src="../img/wechat_friend.png" alt="">
      <img class="share-icon" v-tap="{ methods: share, target: 'weibo' }" src="../img/weibo.png" alt="">
      <img class="share-icon" v-tap="{ methods: share, target: 'qq' }" src="../img/qq.png" alt="">
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      platform: ''
    }
  },
  mounted () {
    this.platform = this.$store.getters.getApp;
  },
  methods: {
    initIOS() {
      window.connectWebViewJavascriptBridge((bridge) => {
        this.webviewBridge = bridge;
      });
    },
    share(target) {
      if (this.platform === 'ios') {
        this.initIOS();
        this.webviewBridge.callHandler('invokeArticleShare', {
          shareTarget: target
        });
      } else if (this.platform === 'android') {
        window.idarex.invokeArticleShare(target);
      }
    }
  }
}
</script>

<style lang="sass">
  @import "../style/component/share.scss";
</style>

仍是看關鍵語句 this.platform = this.$store.getters.getApp; ,這樣咱們能夠取到 state 中的 platform 完成一個完整存取數據的循環。

說到這,不要急着把完整的組件粘貼運行,必定會抱錯的,由於引入了第三方指令庫(v-tap 實現移動端 tap 事件),這些都是次要的也不必還原個人項目,整個原理和流程說的已經很清楚了,直接建立本身的組件跑一下就沒什麼問題了,大同小異。

總結

vuex 的原理其實簡單易懂,本文經過一個小 demo 完成了一個簡單流程,但真實項目裏我不推薦這麼作,最好把 store.js 模塊化,方便後期維護,官方還提供了中間件等概念,準備在項目應用的能夠研讀源代碼,從工程化的角度規劃一下項目,當前 vue2 比較盛行,相信不久在 github 上會有大量的優秀項目供你們參考。

文章出自 orange 的 我的博客 http://orangexc.xyz/
相關文章
相關標籤/搜索