vuex簡單示例

一.vuex是什麼,解決了什麼問題?

官方解釋是:Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化.
我的理解是由於vue各個組件是相對獨立的,要共享數據,就變的很麻煩.vuex就是爲了解決各個組件傳遞數據與共享數據.html

 

二.vuex的核心概念

vuex的核心概念是store,store中包括了state,mutation,action,gettervue

1.state:須要用到的狀態變量
2.mutation:同步修改state
3.action:異步方法和commit mutation
4.getter:至關於computed,主要用做對state進行計算後,生成新的數據狀態ios

通常流程是組件dispatch一個action,action再commit一個mutation,mutation對state作更改;須要計算後的state,則使用getter.es6

 

三.一個簡單的示例

1.需求:
根據id來獲取用戶信息ajax

2.安裝vuex,安裝axios(ajax需求)vuex

3.在src下新建目錄store,創建store.js文件,代碼以下所示axios

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import qs from 'qs'

Vue.use(Vuex)
axios.defaults.baseURL = '/api'

const store = new Vuex.Store({
  state: {
    username: '暫無用戶名,請獲取數據'
  },
  // Vue 建議咱們mutation 類型用大寫常量表示
  mutations: {
    SET_USER_NAME (state, user) {
      state.username = user.name
    }
  },
  actions: {
    getData (context, id) {
      axios.post(
        'http://127.0.0.1:9000/mobile/info',
        qs.stringify({id: id})
      ).then(function (res) {
        context.commit('SET_USER_NAME', res.data)
      }).catch(function (error) {
        console.info(error)
      })
    }
  },
  getters: {
    username: (state) => state.username === '暫無用戶名,請獲取數據' ? state.username : '用戶名:[' + state.username + ']'
  }
})

export default store

  

ps:
a.getters中的username方法並沒有實際做用,只是演示計算生成新的一個狀態數據
b.username用了es6的箭頭函數;等價於:
username(state){
return username: (state) => state.username === '暫無用戶名,請獲取數據' ? state.username : '用戶名:[' + state.username + ']'
}segmentfault

4.main.js中注入store;關鍵代碼api

import store from '@/store/store'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})

  

5.在components中新建query.vue;代碼以下:緩存

<template>
  <div>
    <span>{{ this.$store.getters.username }}</span>
    <input type="text" v-model="id" />
    <button @click="$store.dispatch('getData', id)">獲取數據</button>
  </div>
</template>

<script>
export default {
  data () {
    return {id: 0}
  }
}
</script>

  

6.在App.vue中:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <span>{{ $store.getters.username }}</span>
    <query></query>
  </div>
</template>

<script>
import query from '@/components/query'
export default {
  methods: {

  },
  components: {
    query
  }
}
</script>

  

至此完成了一個簡單的示例

輸入id,點擊獲取數據後

 

四.繼續改進(引入mapState)

以上就是基本的用法,但還有些瑕疵,咱們繼續改進:

1.上面的示例中,在query.vue中咱們常見的應該是用computed屬性去訪問state,由於它是依賴緩存的;代碼改進以下:

<template>
  <div>
    <span>比較好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <input type="text" v-model="id" />
    <button @click="$store.dispatch('getData', id)">獲取數據</button>
  </div>
</template>

<script>
export default {
  data () {
    return {id: 0}
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    username () {
      return this.$store.state.username
    }
  }
}
</script>

  

ps:能夠看到咱們定義了兩個computed屬性,humanUserName和username;前者從store的getters取數據,後者直接從state取數據.

2.咱們在store.js中再增長一些狀態:

const store = new Vuex.Store({
  state: {
    username: '暫無用戶名,請獲取數據',
    sex: '未知',
    age: '0'
  },
  ...........................
})

  

3.在query.vue中咱們仍然打印這些狀態:

<template>
  <div>
    <span>比較好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性別: {{ sex }}</span>
    <br>
    <span>年齡: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="$store.dispatch('getData', id)">獲取數據</button>
  </div>
</template>

<script>
export default {
  data () {
    return {id: 0}
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    username () {
      return this.$store.state.username
    },
    age () {
      return this.$store.state.age
    },
    sex () {
      return this.$store.state.sex
    }
  }
}
</script>

  

你會發現如今的代碼變的冗長了,緣由在於咱們在computed挨個獲取state;改進這一點

 

4.使用Vuex的mapState來改進,改進部分代碼以下

<script>
import {mapState} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 對象中的username, 它至關於 this.$store.state.username,
      age: 'age',
      sex: 'sex'
    })
  }
}
</script>

  

ps:
在...mapState前面的...叫作擴展運算符

五.繼續改進

固然<button @click="$store.dispatch('getData', id)">獲取數據</button>這個也不是很好,應該將他放入組件的methods中

1.改進代碼以下:

<template>
  <div>
    <span>比較好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性別: {{ sex }}</span>
    <br>
    <span>年齡: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="getRemoteData()">獲取數據</button>
  </div>
</template>

<script>
import {mapState} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  methods: {
    getRemoteData () {
      this.$store.dispatch('getData', this.id)
    }
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 對象中的username, 它至關於 this.$store.state.username,
      age: 'age',
      sex: 'sex'
    })
  }
}
</script>

  

2.若是有十個dispatch,this.$store.dispatch('XXX', XXX)這樣的代碼勢必要寫十遍;可使用...mapActions,改進部分代碼以下:

<template>
  <div>
    <span>比較好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性別: {{ sex }}</span>
    <br>
    <span>年齡: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="getRemoteData(id)">獲取數據</button>
  </div>
</template>

<script>
import {mapState, mapActions} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  methods: {
    ...mapActions({getRemoteData: 'getData'})
    /*
    若是名稱相同,能夠直接寫成,...mapActions(['getData'])
    */
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 對象中的username, 它至關於 this.$store.state.username,
      age: 'age',
      sex: 'sex'
    })
  }
}
</script>

  

然還有個...mapGetters,用法和mapState,mapActions是同樣的,在此不作介紹了.

五.增長一個loading提示

如今彷佛是完善了,但忽略了一點是,咱們的數據是從服務器獲取的,因此爲了好的用戶體驗,應該加個loading.在獲取數據的時候顯示,獲取完了隱藏.

1.store.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import qs from 'qs'

Vue.use(Vuex)
axios.defaults.baseURL = '/api'

const store = new Vuex.Store({
  state: {
    username: '暫無用戶名,請獲取數據',
    sex: '未知',
    age: '0',
    waiting: false // loading狀態
  },
  mutations: {
    SET_USER_NAME (state, user) {
      state.username = user.name
    },
    // 顯示和隱藏waiting
    SHOW_WAITING_MESSAGE (state) {
      state.waiting = true
    },
    HIDE_WAITING_MESSAGE (state) {
      state.waiting = false
    }
  },
  actions: {
    getData ({commit}, id) {
      commit('SHOW_WAITING_MESSAGE')
      axios.post(
        'http://127.0.0.1:9000/mobile/info',
        qs.stringify({id: id})
      ).then(function (res) {
        commit('HIDE_WAITING_MESSAGE')
        commit('SET_USER_NAME', res.data)
      }).catch(function (error) {
        console.info(error)
      })
    }
  },
  getters: {
    username: (state) => state.username === '暫無用戶名,請獲取數據' ? state.username : '用戶名:[' + state.username + ']'
  }
})

export default store

  

2.query.vue

<template>
  <div>
    <span v-if="show">正在加載....</span>
    <br>
    <span>比較好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性別: {{ sex }}</span>
    <br>
    <span>年齡: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="getRemoteData(id)">獲取數據</button>
  </div>
</template>

<script>
import {mapState, mapActions} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  methods: {
    ...mapActions({getRemoteData: 'getData'})
    /*
    若是名稱相同,能夠直接寫成,...mapActions(['getData'])
    */
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 對象中的username, 它至關於 this.$store.state.username,
      age: 'age',
      sex: 'sex',
      show: 'waiting'
    })
  }
}
</script>

  

ps:對於store中的actions中的方法

getData (context, id) {
......
}

  

會自動得到一個默認參數context,它是一個store 實例,經過它能夠獲取到store 實例的屬性和方法,如 context.state 就會獲取到 state 屬性, context.commit 就會執行commit命令.其實actions 還能夠簡寫一下, 由於函數的參數是一個對象,函數中用的是對象中一個方法,咱們能夠經過對象的解構賦值直接獲取到該方法。能夠修改以下

getData ({commit}, id) {
......
}

  

本文參考了:

http://www.cnblogs.com/SamWeb/p/6527240.html

https://segmentfault.com/a/1190000009404727

相關文章
相關標籤/搜索