vuex再入門-基礎用法

前言前端

其實我已經用過vuex一段時間了,最近又有一段時間沒有用,結果今天又生疏了。爲此,我決定再入門下。vue

首先vuex是啥?vuex是vue的一個狀態管理器。何爲狀態管理器?狀態管理器能夠理解爲一個小型的前端數據庫。用來實現各個頁面之間的數據共享。java

那爲啥不用sessionStorge和localStorage共享數據呢。由於這裏涉及到狀態更新。當你在a頁面更新了數據後,使用vuex的話,b頁面數據就會自動更新。而使用sessionStorage或者localStorage就沒有這種效果。node

1.使用vuex程序員

1.1 安裝vuexvuex

vuex跟vue是分開的,使用vuex還須要安裝,可使用npm也可使用yarn。代碼以下:vue-cli

npm install vuex -S
或者
yarn add vuex
複製代碼

1.2 引用vuex數據庫

通過上面一個步驟已經安裝了vuex,如今就是咱們使用vuex的時候。使用很簡單,vue的src目錄下新建store文件夾,在store文件夾下新建index.js文件。其實在其餘地方建也能夠,不過這不太符合規範,若是有人改你的代碼的時候就能夠找不到你的store放哪裏。目錄結構以下:npm

|-src
  |- App.vue
  |- assets
  |  |-logo.png
  |-components
  |  |-HelloWorld.vue
  |-main.js
  |-store
  |  |-index.js
複製代碼

1.3 引入vuexjson

在咱們新建的index.js中引入vue和vuex,而且使用vue調用vuex組件,這樣咱們就能夠在index中寫vuex的程序了。

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
複製代碼

寫一個簡單vuex程序。

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }})
  
export default store
複製代碼

在這個程序中,咱們在store中定義了一個字段count,初始值爲0。咱們還定義了一個方法increment,每次調用increament,count值都會加1.

1.4 使用vuex中的數據

1.4.1 注入store

爲了方便咱們使用vuex中的數據,咱們將store加入vue中,這樣之後不管在那裏均可以經過this.$store訪問vuex了。

修改main.js,在new Vue的構造函數中加入store

import Vue from 'vue'
import App from './App.vue'

// 引入store
import store from './store'

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')
複製代碼

1,4,2 使用stroe

假設咱們要在組件helloworld中使用store(vuex)中的數據。就可使用this.$store.state.字段名來獲取store中存放的數據。使用store中的數據也是有要求的——「要放vue的computed屬性中」,你放在其餘地方好比created也行,或者直接賦值給data對象對應的屬性。可是這樣誰有個問題,就是當store中的數據更新的時候,頁面數據不能自動更新。

<template>
  <div class="contain">
    <div class="title">{{name}}</div>
    <p>
      動物園裏單身狗的數量爲:
      <span>{{count}}</span>只
    </p>
    <button @click="addCount">拆散一對情侶</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      name: 'hello world'
    }
  },
  computed: {
    count() {
      return this.$store.state.count
    }
  },
  methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
      console.log('this.$store.state.count:', this.$store.state.count);
    }
  },
}
</script>

<style scoped>
.title {
  font-size: 28px;
  text-align: center;
  margin: 10px;
}
</style>
複製代碼

上面的程序初始的時候,頁面顯示「動物園裏單身狗的數量爲:0」。當咱們點擊「拆散一對情侶」按鈕時,「動物園裏單身狗的數量爲:」就變成了2.

若是咱們把count放在data對象中,好比把js改爲下面這樣子。點擊「拆散一對情侶」按鈕時,store中的count值變了,可是頁面上「動物園裏單身狗的數量」不會變。

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      name: 'hello world',
      count: this.$store.state.count
    }
  },
  methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
      console.log('this.$store.state.count:', this.$store.state.count);
    }
  },
}
複製代碼

1.5 插播一個廣告

使用vue-cli3開發的時候,有時候由於eslint的限制很嚴格,因此致使編譯不經過。能夠修改package.json中eslint的rules。

好比在我項目中,eslint限制我不能寫console,這致使我開發的時候很不方便。我在package.json中把no-console改成0,就去掉了這種限制

"eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "rules": {
      "no-console": 0
    },
    "parserOptions": {
      "parser": "babel-eslint"
    }
  }
複製代碼

以上就是vuex的簡單入門,如下咱們將更加深刻的講解下vuex。

2.vuex的組成

vuex其實很簡單,我之前學習vuex的時候,感受好高深,如今看來仍是蠻簡單的。vuex只由4部分組成,這四部分分別負責不一樣的功能,就至關於遊戲中的4個不一樣的角色吧。4個分別爲:

  • state 用來存儲數據的
  • mutation 以同步的方式來修改數據
  • getters 用來對數據進行過濾和計算,返回計算後的數據
  • action 以異步的方式來修改數據

vuex是單一狀態樹的,就是在整個vue程序中只有一個vuex實例(store)。單一狀態樹可讓咱們很容易的定位代碼的執行狀況。

2.1 state

咱們通常獲取store對象中的數據都是經過this.$store.state.key獲取的。好比咱們獲取count屬性,咱們是這樣獲取的。

this.$store.state.count
複製代碼

2.1.1 mapState函數

咱們獲取state上的值,通常都是放在computed屬性中的,若是state中有不少值,那麼咱們就要在computed中寫不少計算屬性。爲了介紹代碼量,vuex提供了一個mapState函數。

咱們能夠把程序改爲以下這樣子。注意這裏引入了mapState,在computed中咱們也使用了mapState

import { mapState } from 'vuex'
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      name: 'hello world'
    }
  },
  computed: mapState([
    'count'
  ]),
  methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
      console.log('this.$store.state.count:', this.$store.state.count);
    }
  },
}
複製代碼

實現的功能跟以前是同樣的。

computed: mapState([
   'count'
])
// 至關於咱們以前的
computed: {
  count() {
      return this.$store.state.count
  }
}
複製代碼

使用mapState更簡便的方法是使用對象展開符....

computed: {
    ...mapState([
      'count'
    ])
  },
複製代碼

若是想重命名,能夠把mapState的參數改爲對象格式

computed: {
    ...mapState({
      count2: 'count'
    })
  },
複製代碼

2.2 Getters

咱們有時候須要store中state的值進行計算,若是一個組件或者兩個組件的話,咱們能夠直接把屬性放在computed中。可是若是多個組件都須要進行相同的計算的話。咱們代碼就會很冗餘。解決辦法就是在store就對state的值進行計算。所以就要用到store的getters屬性。

在咱們的案例中count表明單身狗的數量,初始值爲0,這個世界是沒有單生狗的。可是某天突然咱們要在vue裏增長一個程序員組件(It.vue)。程序員這個羣體,你們都懂的,單生狗特別多,假設比平均值count多10個,那麼咱們能夠在store中定義一個itDogs的屬性,這個屬性比count值多10。

修改store代碼以下:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  getters: {
    itDogs: state => {
      return state.count + 10
    }
  }
})

export default store
複製代碼

那麼咱們該怎麼獲取呢?

獲取getters中數據能夠經過屬性訪問,也能夠經過方法訪問

2.2.1 經過屬性訪問

經過屬性訪問代碼以下:this.$store.getters.健名,在這個需求中就是:

this.$store.getters.itDogs
複製代碼

It.vue 中獲取itDogs代碼以下:

computed: {
    itDogs: function () {
      return this.$store.getters.itDogs
    }
 }
複製代碼

2.2.2 經過方法訪問

要想經過方法訪問,那麼getters中的屬性,在定義的時候必須返回一個函數,而不是直接返回值

假設咱們的需求改變了,在程序員的世界裏,使用不一樣語言的單身狗的數量是不同的。好比使用js的就是在平均單身狗的數量上加10,使用java的就是平均的基礎上加100

那麼能夠把getters裏寫itDogs寫成一個函數,根據不一樣的語言傳入不一樣的值,而後返回對應的結果。(固然也能夠用其餘方法)

store修改以下:

getters: {
    itDogs: state => (num) => {
        return state.count + num
    }
}
複製代碼

獲取方法以下:

computed: {
    itDogs: function () {
      return this.$store.getters.itDogs(100)
    }
  },
複製代碼

**經過屬性方法訪問getters中的值,這個值會被緩存起來。下次須要時能夠直接從緩存中拿。經過方法訪問的話,每次都要調用函數從新計算

2.2.3 訪問其餘getter

getter也能夠接受其餘getter做爲第二個參數。好比男程序員單身狗的數量在通常的程序員單身狗的數量上又加100.

getters: {
    itDogs: state => (num) => {
      return state.count
    },
    manItDogs: (state, getters) => {
      return getters.itDogs + 100
    }
  }
複製代碼

2.2.4 mapGetters函數

mapGetters函數將store中getter映射到局部計算屬性,好比getter是以下:

getters: {
    itDogs: state => {
      return state.count
    },
    manItDogs: (state, getters) => {
      return getters.itDogs + 100
    }
  }
複製代碼

獲取的代碼咱們修改以下:

computed: {
    ...mapGetters([
      'itDogs',
      'manItDogs'
    ])
  },
複製代碼

若是要重命名,能夠把mapGetters的參數改爲對象

computed: {
    ...mapGetters({
      itDogs2: 'itDogs',
      manItDogs2: 'manItDogs'
    })
  },
複製代碼

2.3 Mutation

更改 Vuex 的 store 中的數據的惟一方法是提交 mutation。須要如今store中註冊事件,後面才能調用。mutation中定義的函數必須是同步的。

好比咱們以前定義的

mutations: {
    increment(state) {
      state.count++
    }
  },
複製代碼

咱們想要count的數量加1,咱們就調用

this.$store.commit('increment')
複製代碼

2.3.1 傳參

咱們以前定義了一個按鈕叫「拆散一對情侶」。點擊這個按鈕咱們就把count的數量加2,咱們以前是這樣調用的。

methods: {
    addCount() {
      this.$store.commit('increment')
      this.$store.commit('increment')
    }
  },
複製代碼

咱們調用了兩次commit,這顯得很奇怪,其實mutations中的函數是能夠傳參的。咱們修改increment函數。

mutations: {
    increment(state, num) {
      state.count += num
    }
  },
複製代碼

state.count再也不是加1了,而是加上num。這樣好了,不管是3p的仍是百人斬的,咱們均可以拆散了。

修改調用函數以下:

methods: {
    addCount() {
      this.$store.commit('increment', 2)
    }
  },
複製代碼

2.3.2 對象參數

有時候咱們參數不少怎麼辦?咱們能夠把第二個參數改爲對象。

修改increment

mutations: {
    increment(state, obj) {
      state.count += obj.num
    }
  },
複製代碼

修改調用

methods: {
    addCount() {
      this.$store.commit('increment', {
        num: 2
      })
    }
  },
複製代碼

2.3.3 mapMutations

mapMutations能夠將store中mutation中的方法映射爲vue組件中methods的方法

methods: {
    ...mapMutations([
      'increment'
    ])
  },
複製代碼

這樣咱們調用組件的increment方法,就至關於調用stroe中mutation的increment方法

調用以下

<button @click="increment({num:2})">拆散一對情侶</button>
複製代碼

2.4 Action

Action 相似於 mutation,不一樣在於:

  • Action 提交的是 mutation,而不是直接變動狀態。
  • Action 能夠包含任意異步操做

一個簡單的action以下

actions: {
    increment: (context, obj) => {
      setTimeout(() => {
        context.commit('increment', obj)
      }, 5000);

    }
  }
複製代碼

action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters

如何調用action呢?咱們可使用dispatch來調用

this.$store.dispatch('increment')
複製代碼

完整代碼:

methods: {
    increment: function () {
      this.$store.dispatch('increment', { num: 2 })
    }
  },
複製代碼

actions函數跟mutation函數同樣都是能夠傳參的。

2.4.1 mapActions

mapActions將action中的方法,映射到vue實例methods方法上。

methods: {
    ...mapActions([
      'increment'
    ])
  },
複製代碼

調用

<button @click="increment({num:2})">5秒後拆散一對情侶</button>
複製代碼

2.4.2 組合多個action

store.dispatch能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch 仍舊返回 Promise

假設咱們的action以下

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
複製代碼

那麼咱們在組件裏能夠這樣處理:

store.dispatch('actionA').then(() => {
  // ...
})
複製代碼

在另外一個action裏的話,能夠這樣調用

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}
複製代碼

總結:以上咱們vuex的基本用法都講完了,以上知識點基本上能夠解決咱們工做中面臨的問題了。可是vuex還有些更加高深的用法,咱們下一節再講

相關文章
相關標籤/搜索