vuex 學習記錄

vuex

vuex是一個專門爲vue.js應用程序開發的狀態管理模式,它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。html

vueX有幾個核心的概念:vue

  • Statees6

  • Gettersweb

  • Mutationsvue-router

  • Actionsvuex

  • Modulesvue-cli

首先咱們用vue-cli構建一個vue目錄,如圖所示npm

clipboard.png]json

其中有三個vue組件,app.vue,hello.vue,content.vue,在router目錄的index.js定義了路由關係。數組

import Vue from 'vue'
    import Router from 'vue-router'
    import Hello from '@/components/Hello'
    
    Vue.use(Router);
    
    
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'Hello',
          component: Hello
        }
      ]
    })

APP.vue

<template>
    <div id="app">
      <h1>{{ msg }}</h1>
      <router-view></router-view>
    </div>
  </template>
  
  <script>
  export default {
      name: 'app',
      data(){
          return {
            msg: 'Welcome to Your App.vue components'
          }
      },
  }
  </script>

hello.vue

<template>
        <div class="hello">
          <h1>{{ msg }}</h1>
          <contents></contents>
        </div>
      </template>
      
      <script>
      import contents from './Content';
      
      export default {
        name: 'hello',
        data () {
          return {
            msg: 'Welcome to Your Hello.vue components'
          }
        },
        components:{
          contents
        }
      }
      </script>

content.vue

<template>
      <div id="inner">
            <h2>{{msg}}</h2>
      </div>
   </template>
   
   
   <script>
   export default{
       name:'content',
       data(){
           return {
               msg:'Welcome to Your Content.vue components'
           }
       }
   }        
   </script>

經過上面的三個組件和路由咱們能夠看出,訪問跟路徑,app組件引入hello組件,hello.vue嵌套content.vue組件,跟main.js同級建一個store.js,定義vuex的store和簡單的mutations

import vue from 'vue';
  import vuex from 'vuex';
  
  
  vue.use(vuex);
  
  
  export default new vuex.Store({
    state:{
       time:new Data().getTime(),
       names:["張三"],
    }
  })

修改main.js,添加vuex的使用

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

這個時候這個項目已經把 store 的實例注入全部的子組件,裏面有一個state對象和mutations對象,state包括了所有的狀態,做爲一個惟一數據源存在,vue項目裏面能夠在任意組件裏面引用state裏面的屬性,

如何在vue組件引入state,幾種經常使用的辦法

  1. 經過 js {{ this.$store.state.time }} 能夠直接訪問store定義的state對象

  2. 計算屬性中返回某個狀態

    computed:{
       count(){
    return this.$store.state.time;
       }
     }
  3. 當一個組件獲取多個狀態,上面兩種使用方式比較重複和冗餘,爲了解決這個問題,咱們可使用mapState輔助函數

    import {mapState} from 'vuex'
       
       
       export default {
         
         computed:mapState([
      'time'
         ])
       
       }
  • mapState返回一個對象,映射this.count爲this.$store.state.time,mapState裏面參數是數組形式,參數名和state同名

    import {mapState} from 'vuex'
    
    
    computed:mapState({
       time:state=>state.time,
       nameArr:'names'
    })
  • 這種方式的mapState形參是一個對象,第一個count使用箭頭函數,返回state.count,第二個修改了names的別名變成nameArr

Mutations

咱們修改store.js,經過添加mutations,來改變store裏面的state。更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutations 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數

export default new vuex.Store({
     state:{
       time:new Date().getTime(),
       names:["張三"]
     },
     mutations:{
       pushName (state,thisName){
         state.names.push(thisName.name)
       }
     }
   })

咱們修改app組件,

<label>
        <input type="text"  v-model="addName" />
        <button @click="addNameFn">添加</button>
   </label>
  <p>姓名:
            <span v-for="name in nameArr">{{ name }} &nbsp;&nbsp;</span>
   </p>
export default {
        name: 'app',
        data(){
            return {
              msg: 'Welcome to Your App.vue components',
              addName:''
            }
        },
        computed:mapState({
              nameArr:'names'
        }),
        methods:{
            addNameFn(){
                var that=this;
                this.$store.commit('pushName',{name:that.addName})               
            }
          
        }  
    }

Mutations必須是同步函數,由於每一條 mutation 被記錄,devtools 都須要捕捉到前一狀態和後一狀態的快照。然而 mutation 在異步函數中的回調讓這不可能完成
調用方式有三種

  1. 使用this.$store.commit調用,第一個參數是Mutations裏面定義的方法名,第二個參數是傳入的形參,建議應該是一個對象,能夠包含多個字段,而且會更容易閱讀代碼

    addNameFn(){
     this.$store.commit('pushName',{
      name:this.addName
     })
      }
  2. 使用 type屬性對象,commit調用的參數只有一個是一個對象,type是Mutations裏面定義的方法名,其餘字段是形參

    addNameFn(){
     this.$store.commit({
       type:'pushName',
       name:this.addName
     })
       }
  3. 使用mapMutations,引入 mapMutations ,將methods 映射爲 store.commit 調用

    import {mapMutations} from 'vuex'
      
       methods:{
      ...mapMutations([
          'pushName'
      ]),
       
      addNameFn(){
        this.pushName({name:that.addName})
      }
       }

Getters

有時候咱們須要根據store中的state中的屬性派生一些值,例如統計添加的姓名總數,若是有多個組件須要用到統計姓名總數這個值,咱們要麼是在每一個組件中重複寫一個方法,要麼是
寫一個公用的方法,每一個組件引入,這兩種方法都不是很理想,因此引入了Getters,能夠認爲是store的計算屬性,首先添加getters,添加一個統計添加的姓名總數的方法,而且在每一個組件打印這個總數

修改store.js,添加getters屬性,添加getNameLen方法,參數是state

export default new vuex.Store({
     state:{
       time:new Date().getTime(),
       names:["張三"]
     },
     mutations:{
       pushName (state,thisName){
         state.names.push(thisName.name)
       }
     },
     getters:{
       getNameLen:state=>{
         return state.names.length
       }
     }
   })

修改App.vue的template,直接打印添加姓名的個數

<label>
        <input type="text" v-model="addName"/>
        <button @click="addNameFn">添加</button>
  </label>
  
  <p>姓名:
        <span v-for="name in nameArr">{{ name }} &nbsp;&nbsp;</span>
  </p>
  <p>人數:{{ this.$store.getters.getNameLen }}</p>

修改完這些,咱們發現當咱們添加一個姓名,每一個組件都會更新添加的姓名的總條數,getters調用就是這麼簡單,上面只是一種調用方式,除此外還有兩種調用方式

1.在計算屬性中引入

<p>人數:{{ getNameLen }}</p>
computed: {
          nameCount(){
              return  this.$store.getters.getNameLen
          }
     }

2.使用 mapGetters,引入mapGetters,使用個結構賦值的方法,將getters裏面的方法映射到局部計算屬性上,若是是數組則跟getters裏面的方法名同名,對象能夠修更名稱,同mapState同樣

<p>人數:{{ getNameLen }}</p>
import {mapGetters} from 'vuex'
 
 computed: {
       ...mapGetters([
         "getNameLen"
       ]),
       ...mapState({
         nameArr: 'names',
       })
  }

Actions

Action相似於mutation,不一樣在於

  • action能夠包含異步操做,而mutation只能是同步的

  • mutation是直接修改state裏面的數據狀態,並且action是commit一個mutation來記錄修改狀態。

讓咱們經過一個簡單例子來實現一個簡單的action:

1.修改 config index.js,引入url模塊,修改dev配置裏面的proxyTable,建一個與src同級的static目錄,裏面放一個
getName-time0.json文件,模擬本地http請求返回的json數據,重啓服務, npm run dev 訪問 http://localhost:8080/dataweb/getName?time=0
就能請求到static裏面的json文件

url=require('url');

   proxyTable: {
         '/dataweb': {
           target: 'http://localhost:8080',
           changeOrigin: true,
           pathRewrite: function(path, req) {
             var urlParsed = url.parse(req.url, true),
               query = urlParsed.query,
               pathname = urlParsed.pathname.replace(/\/*$/g,'');
             pathname = pathname.substring(pathname.lastIndexOf('/'));
             Object.keys(query).forEach((key) => {
               pathname += ('-' + key + query[key]);
             });
             pathname = '/static' + pathname + '.json';
             console.log('proxy request ' + path + ' to ' + pathname);
             return pathname;
           }
         }
       }
{
    "data":["趙錢","王五","孫劉"]
  }
  1. 建立actions,修改store.js,引入vue-resource,actions是經過提交mutations來修改狀態,因此在mutations增長一個getNames方法
    state裏面增長一個data字段記錄數據,actions增長一個getData方法。getDate有一個默認的context參數,這個參數具備跟store實例相同的屬性和方法
    經過調用context.commit提交一個mutation,或者咱們能夠經過es6裏面的結構賦值傳入一個{commit},第二個參數 _param是咱們分發action傳入的參數

    import Vue from 'vue';
    import vuex from 'vuex';
    import VueResource from 'vue-resource';
    
    Vue.use(VueResource);
    Vue.use(vuex);
    
    export default new vuex.Store({
      state:{
     time:new Date().getTime(),
     data:[],
     names:["張三"]
      },
      mutations:{
     pushName (state,thisName){
       state.names.push(thisName.name)
     },
     getNames(state,data){
       state.data=data.list;
     }
    
      },
      getters:{
     getNameLen:state=>{
       return state.names.length
     }
      },
      actions:{
      getData({ commit },_param){
        return Vue.http.get('/dataweb/getName',{
          params:_param.data
        }).then((respons)=>{
          commit({
            type:'getNames',
            list:respons.data
          });
        })
      }
      }
     })
  2. 修改app.vue組件,template裏面增長一個按鈕

    <button @click="searchName">顯示所有姓名</button>
     <p><span v-for="values in nameData">{{ values }} &nbsp;&nbsp;</span></p>

data數據裏面增長一個_data存儲數據,methods裏面增長一個searchName方法,派發getDate事件,而且傳入data參數,actions的方法返回的promise,能夠被store.dispatch 處理,而且store.dispatch 仍舊返回一個promise
getData裏面的promise返回成功則更新this._data數據,失敗則輸出獲取數據失敗

data(){
          return {
            msg: 'Welcome to Your App.vue components',
            addName: '',
            nameData:[],
          }
    },
                   
    methods: {
      searchName(){
         this.$store.dispatch({
            type:'getData',
            data:{ time:0 }
         }).then(()=>{
            this.nameData=this.$store.state.data
         },()=>{
            console.log('獲取數據失敗')
         })
             
      }
    
    }

從上面的例子咱們瞭解到,點擊一個按鈕發生了這些操做;

  1. 定義一個getData的action 異步調用一個請求,請求成功,commit一個getNames的mutations,修改state的data數據

  2. 執行searchName事件,用$store.dispatch派發一個getData的actions,而且傳入data:{time:0}的參數

  3. dispatch返回的promise成功,就表示getDate裏面的commit已經執行完畢,state.data已經有數據,更新當前this._nameData,循環輸出數據

在methods派發action除了實例的這種以對象形式派發,還有三種

  • 以載荷方式

    this.$store.dispatch('increment',{
             data:{
               time:1
             }
      })
  • 在methods裏面使用 mapActions 方式 映射action

    import {mapActions} from 'vuex';
    
      //數組形式  調用直接this.getDate
      ...mapActions([
            'getData'
       ]),
      
      //對象形式   this.searchName  等同於 this.getData
      ...mapActions({
          searchName:'getData'
       })

    修改methods裏面的searchName方法

    searchName(){
            this.getDate({
              data:{
                time:0
              }
            }).then(()=>{
              this.nameData=this.$store.state.data
            },()=>{
              console.log('數據失敗')
            })
          }

vuex還有一個Modules概念,本篇文章就介紹這麼多了,等學習完modules,在補充。。。。。

相關文章
相關標籤/搜索