Vuex入门教程

前言

组件化应用构建是Vue的特色之一,所以咱们在Vue的实际开发过程当中会常常须要封装自定义组件,以提升开发的效率。 而组件在大部分状况下并不会孤立的存在,它必然会与父组件和兄弟组件产生数据的交互。因此在这里为你们总结两种组件数据交互的方式:EventBus和利用Vuex框架进行状态管理。vue

上一篇文章介绍了若是经过EventBus在Vue自定义组件中进行事件传递(Vue自定义组件事件传递:EventBus部分),而EventBus比较适合在中小型项目中使用;若是咱们须要开发一套大型的项目,这时候咱们应该考虑使用Vuex框架来统一进行数据状态管理。es6

为了方便读者理解Vuex的基本使用,我将继续沿用上一篇文章的案例(显然在单页和中小型应用中,Vuex显得不太必要),为你们介绍Vuex的使用。vuex

为何有EventBus还要使用Vuex

为何咱们有EventBus了,还要使用Vuex?bash

其实在Vuex官网就有很好的解释:Vuex官网对Vuex是什么的解释app

对于Vuex是什么,个人理解是:框架

Vuex是数据状态管理框架,主要作到了数据和视图层的解耦ecmascript

而已经有EventBus咱们为何还要使用Vuex这个问题上,个人理解是:异步

咱们仔细思考一下,当咱们使用EventBus时,咱们A控件给B控件和C控件传递数据后,B控件通过处理又要修改传递过来数据,继续通知A控件和C控件修改数据,这样在C文件中就要多处监听A和B的EventBus。这样当有关于数据传递有bug时,咱们就很难追溯究竟是哪个环节出了问题。ide

伴随着咱们业务的复杂程度变高,视图的复杂度也会随之升高,因此此时经过Vuex来对数据和视图层解耦就显得十分必要。模块化

案例介绍(与上一篇"Vue自定义组件事件传递:EventBus部分"案例一致,可跳过)

本章节会有大量的代码示例,为了让读者阅读轻松,作以下目录和组件介绍。本章节主要运用了两个子组件和一个父组件。

子组件文件名:SearchInput.vueSearchItem.vue

父组件文件名:StateView.vue

目录结构展现:

一、SearchInput.vue

组件介绍:一个输入框,它会onInput方法去监听输入内容,并调用方法,将输入框内的数据传递出去。

代码展现:

<template>
  <div>
    <input placeholder="搜索内容"  v-model="searchContent"/>
  </div>
</template>

<script type="text/ecmascript-6">
  export default{
    data(){
      return{
        searchContent:""
      }
    },
    props:{

    }
  }
</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>


复制代码

SearchItem.vue

组件介绍:一个span,它主要用来接收父组件传递的内容和接收同胞组件输入框传递的内容,并进行展现。

代码示例:

<template>
    <span class="item">
      {{content}}
    </span>
</template>

<script type="text/ecmascript-6">
  export default{
    data(){
      return{
        content:this.itemContent
      }
    },
    props:{
      itemContent:{
        type:String,
        required:true
      }
    }
  }
</script>

<style lang="stylus" rel="stylesheet/stylus">
  .item
    background #f4f4f4
    padding 3px 5px
    box-sizing border-box
    display inline-block
    cursor pointer
</style>

复制代码

StateView.vue

组件介绍:父组件,主要展现页面和加载子组件

代码示例:

<template>
  <div>
    <search-view></search-view>
    <div>
      <search-item :itemContent="content"/>
      <search-item itemContent="热门搜索2"/>
      <search-item itemContent="热门搜索3"/>
    </div>
    <div>{{content}}</div>

  </div>
</template>

<script type="text/ecmascript-6">
import searchView from '../components/SearchInput.vue'
import searchItem from '../components/SearchItem.vue'

export default{
  data () {
    return {
      content:"接收输入框的值"
    }
  },
  components: {
    searchView,
    searchItem
  }
}

</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>

复制代码

正文

全局注册Vuex

在开始介绍Vuex的内容前,咱们须要在全局中注册一个Vuex对象。

查看咱们的目录结构:

一、建立Store文件

咱们建立了一个store文件夹,专门存放各类类型的store文件。

在这咱们建立了SearchStore.js文件。它就是咱们接下来主要的主角,关于Vuex的State、Getter、Mutation、Action都会围绕它来展开。

SearchStore.js代码以下:

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex)
export default new vuex.Store({
})

复制代码

二、在main.js中注入SearchStore.js

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import vueResource from 'vue-resource'
import searchStore from './store/SearchStore'   //引入SearchStore.js
Vue.use(vueResource)
Vue.config.productionTip = false

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

复制代码

咱们在main.js中引入了SearchStore.js文件,并在Vue根组件中注入了SearchStore.js文件,所以全部的子组件都能访问到了这个SearchStore.js这个Store。

State

State就像一个全局的数据仓,里面存放着数据源

这句话怎么理解呢?

不急,咱们看一个Demo例子,你就会对State一下就理解了。

咱们修改SearchStore.js的文件,给它加一个数据仓,即State:

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex)
export default new vuex.Store({
  state:{
    searchContent:"这是Store的searchContent内容"
  }
})

复制代码

而后咱们在StateView.jsSearchInput.js的mounted()生命周期中去打印SearchStore.js中的searchContent:

StateView

<template>
  <div>
    <search-view></search-view>
    <div>
      <search-item :itemContent="content"/>
      <search-item itemContent="热门搜索2"/>
      <search-item itemContent="热门搜索3"/>
    </div>
    <div>{{content}}</div>

  </div>
</template>

<script type="text/ecmascript-6">
import searchView from '../components/SearchInput.vue'
import searchItem from '../components/SearchItem.vue'
import searchEvent from '../event/SearchEvent'
export default{
  data () {
    return {
      content:""
    }
  },
  mounted(){
    console.log("StateView======"+this.$store.state.searchContent)   //打印SearchStore中的searchContent
  },
  components: {
    searchView,
    searchItem
  }
}

</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>

复制代码

SearchInput.js

<template>
  <div>
    <input placeholder="搜索内容" @input="sendEvent" v-model="searchContent"/>
  </div>
</template>

<script type="text/ecmascript-6">
  import searchEvent from '../event/SearchEvent'
  export default{
    data(){
      return{
        searchContent:""
      }
    },
    mounted(){
      console.log("SearchInput======"+this.$store.state.searchContent)
    },
    props:{

    }
  }
</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>

复制代码

控制台输出结果

怎么样,对state有感受了嘛?

State的感觉结论:

一、state是一个数据存储的仓库,全部的数据源都会存放在这里,就相似组件中的data。

二、咱们能够明显感受到,咱们在SearchStore.js的state中的数据,能够在任意组件中经过this.$store.state访问到,而不是像使用EventBus同样,须要处处去调用$emit$on方法去监听数据和拷贝数据副本,作到了数据和视图层的解耦。

Getter

Getter 用来在获取数据源的时候,对数据源进行必定的加工后再返回。

接下来咱们在SearchStore.js中加入Getter,来感觉下上面这句话所表达的意思。

SearchStore.js

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex)
export default new vuex.Store({
  state:{
    searchContent:"这是Store的searchContent内容"
  },
  getters:{     //在这里加入getter
    getSearchContent(state){       
    //咱们定义了一个getter函数,叫作gerSearchContent,它有一个参数,这个参数保存了state对象。
    //即SearchStore.js的state对象
      return "加工后的searchContent===="+state.searchContent     //模拟加工数据,并将加工后的数据返回
    }
  }
})
复制代码

在这里,咱们在Store的getters中定义了一个getSearchContent的函数,这个函数接收一个参数,这个参数就是咱们的state对象,在这个例子中,即:SearchStore.js的state对象。

而后咱们模拟了数据加工的过程,返回一个数据加工后的数据。

接下来,让咱们在StateView的mounted()生命周期中,打印这个getter。

StateView.js

<template>
  <div>
    <search-view></search-view>
    <div>
      <search-item :itemContent="content"/>
      <search-item itemContent="热门搜索2"/>
      <search-item itemContent="热门搜索3"/>
    </div>
    <div>{{content}}</div>

  </div>
</template>

<script type="text/ecmascript-6">
import searchView from '../components/SearchInput.vue'
import searchItem from '../components/SearchItem.vue'
import searchEvent from '../event/SearchEvent'
export default{
  data () {
    return {
      content:""
    }
  },
  mounted(){
    console.log("StateView======"+this.$store.state.searchContent)   //打印SearchStore中的searchContent
    console.log("StateView======"+this.$store.getters.getSearchContent)  //打印SearchStore中的getSearchContent
  },
  components: {
    searchView,
    searchItem
  }
}

</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>
复制代码

控制台输出的结果

Getter的感觉结论

一、getter主要用于在获取数据时,对数据进行加工后返回。

二、与EventBus相比,经过Vuex的Getter,咱们能够在Store中对数据作统一加工处理,利于往后的项目维护。

Mutation

对数据仓中的数据,进行修改。Mutation只支持同步方法

一样,咱们经过在SearchStore.js加入Mutation来感觉Mutation的做用

SearchStore.js

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex)
export default new vuex.Store({
  state:{
    searchContent:"这是Store的searchContent内容"
  },
  getters:{
    getSearchContent(state){
      return "加工后的searchContent===="+state.searchContent
    }
  },
  mutations:{
    changeSearchContent(state,payload){
      /**
       * 传递单个数据参数
       */
      state.searchContent=payload     //修改state的searchContent数据
    },
    changeSearchContentByObject(state,payload){
      /**
       * 有时候咱们须要再payload传递多个数据参数时,咱们能够经过对象的方式传递
       */
      state.searchContent="经过Object对象来修改数据:"+payload.searchContent
    }
  }
})
复制代码

注意:上面咱们定义了两个Mutation方法,他们惟一的不一样是一个接受的payload是单个参数;而在须要传递多个参数时,咱们能够在payload中传递对象的方式,去传递多个参数。

接下来咱们依旧修改StateView.js。

StateView.js

<template>
  <div>
    <search-view></search-view>
    <div>
      <search-item :itemContent="content"/>
      <search-item itemContent="热门搜索2"/>
      <search-item itemContent="热门搜索3"/>
    </div>
    <div>{{content}}</div>

  </div>
</template>

<script type="text/ecmascript-6">
import searchView from '../components/SearchInput.vue'
import searchItem from '../components/SearchItem.vue'
import searchEvent from '../event/SearchEvent'
export default{
  data () {
    return {
      content:""
    }
  },
  mounted(){
    console.log("StateView======"+this.$store.state.searchContent)   //打印SearchStore中的searchContent
    console.log("StateView======"+this.$store.getters.getSearchContent)  //打印SearchStore中的getSearchContent
    
    //经过this.$store.commit()方法修改state的searchContent参数
    //在payload中传递单个参数
    this.$store.commit("changeSearchContent","StateView中修改后的SearchContent")
    console.log("StateView======"+this.$store.state.searchContent)
    
    //当须要传递多个参数时,咱们能够在payload中以对象的形式传递
    this.$store.commit("changeSearchContentByObject",{"searchContent":"StateView中修改后的SearchContent","testVal":"testVal"})
    console.log("StateView======"+this.$store.state.searchContent)
  },
  components: {
    searchView,
    searchItem
  }
}

</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>
复制代码

StateVie.js中,咱们经过this.store.commit()方法去调用mutations中的方法,它接收两个参数:

一、第一个参数传递mutations中对应的方法名 二、第二个参数传递payload,即要传递的数据

控制台输出的结果

Mutation的感觉结论:

一、经过Mutation咱们能够对数据仓中的数据进行修改,咱们能够在组建中经过调用this.$store.commit()方法去调用对应的Mutation去修改数据。

二、Mutation中只能执行同步的方法,若是须要执行异步方法,咱们要使用接下来即将登场的Action。

Action

Action和Mutation相似,他们之处在于:一、Action 提交的是 mutation,而不是直接变动状态。二、Action 能够包含任意异步操做。

话很少说,咱们直接修改SearchStore.js文件:

SearchStore.js

import Vue from 'vue'
import vuex from 'vuex'
Vue.use(vuex)
export default new vuex.Store({
  state:{
    searchContent:"这是Store的searchContent内容"
  },
  getters:{
    getSearchContent(state){
      return "加工后的searchContent===="+state.searchContent
    }
  },
  mutations:{
    changeSearchContent(state,payload){
      /**
       * 传递单个数据参数
       */
      state.searchContent=payload     //修改state的searchContent数据
    },
    changeSearchContentByObject(state,payload){
      /**
       * 有时候咱们须要再payload传递多个数据参数时,咱们能够经过对象的方式传递
       */
      state.searchContent="经过Object对象来修改数据:"+payload.searchContent
    }
  },
  actions:{
    changeSearchContentByAction(context,payload){
      /**
       * 模拟异步的过程,2000毫秒后经过commit()方法执行mumations中的changeSearchContentByObject方法改变数据
       * 一样,payload能够是单数据或经过对象的方式,传递多个数据
       * 这里只举例经过对象传递多数据的状况
       */
      setTimeout(()=>{
        context.commit("changeSearchContentByObject",payload)
      },2000)
    }
  }
})
复制代码

在这里咱们模拟了异步的过程,经过调用setTimeOut()函数,在2000毫秒后经过调用commit()函数来改变searchContent数据。

接下来咱们来修改StateView.js来调用咱们刚刚写的changeSearchContentByAction

StateView.js

<template>
  <div>
    <search-view></search-view>
    <div>
      <search-item :itemContent="content"/>
      <search-item itemContent="热门搜索2"/>
      <search-item itemContent="热门搜索3"/>
    </div>
    <div>{{content}}</div>

  </div>
</template>

<script type="text/ecmascript-6">
import searchView from '../components/SearchInput.vue'
import searchItem from '../components/SearchItem.vue'
import searchEvent from '../event/SearchEvent'
export default{
  data () {
    return {
      content:""
    }
  },
  mounted(){
    console.log("StateView======"+this.$store.state.searchContent)   //打印SearchStore中的searchContent
    console.log("StateView======"+this.$store.getters.getSearchContent)  //打印SearchStore中的getSearchContent
    
    //经过this.$store.commit()方法修改state的searchContent参数
    //在payload中传递单个参数
    this.$store.commit("changeSearchContent","StateView中修改后的SearchContent")
    console.log("StateView======"+this.$store.state.searchContent)
    
    //当须要传递多个参数时,咱们能够在payload中以对象的形式传递
    this.$store.commit("changeSearchContentByObject",{"searchContent":"StateView中修改后的SearchContent","testVal":"testVal"})
    console.log("StateView======"+this.$store.state.searchContent)
    
    //经过Action修改数据
    this.$store.dispatch("changeSearchContentByAction",{"searchContent":"action修改后的数据"})
    setTimeout(()=>{
      console.log("5000毫秒后StateView======"+this.$store.state.searchContent)
    },5000)
    
  },
  components: {
    searchView,
    searchItem
  }
}

</script>

<style lang="stylus" rel="stylesheet/stylus">

</style>
复制代码

咱们在StateView.js中,经过this.$store.dispatch()函数去调用action,该函数接收两个参数: 一、Store中Action对应的方法名 二、要传递的数据

** 控制台输出结果**

Action的感觉结论:

一、Action和Mutation相似,它只是可以处理异步的状况,最终经过commit()函数调用Mutation去修改数据。

二、经过this.$store.dispatch()去调用Action的方法。

Module

能够将Store模块化,而后经过Module整合在一块儿。

咱们若是将全部的数据都写入一个Store的state中,这时候咱们获取,修改数据。随着项目不断变大,咱们这个Store中的state和Mutation、Getter、Action的数量和Store的代码行数就会爆炸性的增长,使得咱们的Store变得维护困难。

这时候,咱们但愿把Store模块化,例如不一样子组件的数据抽取出来写成单独的一个Store。

这时候咱们就须要经过Module整合各个模块,而后在将Store挂在在根组件下。

如今咱们再也不以SearchStore举例了,咱们建立3个新的Store文件

一、index.js Store,主要负责整合全部的Store模块。

二、SearchInputStore.js, 主要负责输入框子组件SearchInput.js的数据维护

三、SearchItemStore.js,主要负责SearchItem.js子组件的数据维护

首先咱们来看SearchInputStore.js和SearchItemStore.js:

SearchInputStore.js

export default {
  state: {
    searchContent:""
  },
  getters:{
    getSearchContent(state){
      return state.searchContent;
    }
  },
  mutations:{
    changeSearchContent(state,payload){
      state.searchContent=payload
    }
  }
}
复制代码

SearchItemStore.js

export default {
  state: {
    searchHistoryList:[]
  },
  getters:{
    getsearchHistoryList(state){
      return state.searchHistoryList;
    }
  },
  mutations:{
    changesearchHistoryList(state,payload){
      state.searchContent.push(payload)
    }
  }
}
复制代码

这里,咱们只是经过export default将SearchInputStore和SearchItemStore输出。

接下来让咱们看index.js,它将SearchInputStore.jsSearchItemStore.js整合在一块儿

index.js

/**
 * Created by Vicky on 2018/6/22.
 */
import Vue from 'vue'
import vuex from 'vuex'
import searchInputStore from './SearchInputStore'
import searchItemStore from './SearchItemStore'
Vue.use(vuex)
export default new vuex.Store({
  modules:{
    searchInputStore:searchInputStore,
    searchItemStore:searchItemStore
  }
})

复制代码

在index中咱们首先将SearchInputStore.jsSearchItemStore.js经过import引入,而后在Store的modules中将它们两引入。

接下来咱们将index.js挂载在根组件下,咱们修改一下main.js:

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import vueResource from 'vue-resource'
import store from './store/index'   //引用index.js
// import searchStore from './store/SearchStore'
Vue.use(vueResource)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,    //修改部分,简写
  components: { App },
  template: '<App/>'
})
复制代码

这样咱们就成功整合了两个Store模块,须要注意的是接下来咱们访问state对象的对象时,须要加上模块名

例如,咱们要访问SearchInputStore的searchContent的数据时,咱们须要使用this.$store.state.searchInputStore.searchContent进行访问。

namespaced: true

namespaced主要用于提升模块的封装性和复用性

咱们会遇到一个状况,咱们不一样模块的Store中可能会存在相同方法名的Mutation、Getter和Action,这时候咱们调用commit()会调用全部相同方法名的Mutation;当咱们Getter方法名重复时,会报错;当咱们调用dispatch()方法时,全部相同方法名的Action都会被执行。

这明显是不符合常理的,它会对其余模块的数据形成污染和异常。但在一个大型项目中,咱们每每是多人协同开发的,因此咱们很难避免你们在未告知的状况下,定义了相同名字的Mutation、Getter和Action。

此时,咱们就须要namespaced来帮咱们忙,以提升模块的封装性和复用性。

接下来咱们来修改index.jsSearchInputStore.js文件:

index.js

import Vue from 'vue'
import vuex from 'vuex'
import searchInputStore from './SearchInputStore'
import searchItemStore from './SearchItemStore'
Vue.use(vuex)
export default new vuex.Store({
  state:{
    rootVal:"根节点Store的值"
  },
  getters:{
    getRootVal(state){
      return state.rootVal
    }
  },
  mutations:{
    changeRootVal(state,payload){
        console.log("根节点Store的changeRootVal被调用了")
        state.rootVal=payload
    }
  },
  actions:{
    changeRootValByAction(context,payload){
      console.log("根节点Store的changeRootValByAction被调用了")
      context.commit("changeRootVal",payload)
    }
  },
  modules:{
    searchInputStore:searchInputStore,
    searchItemStore:searchItemStore
  }
})


复制代码

咱们给index.js加了State、Getter和Mutation,这是为了在后面演示子Store经过namespaced对数据模块进行封装后,子Store如何去访问根Store的Getter、若是经过commit()调用根Mutation和子Mutation;如何经过dispatch()调用根Action和子Action。

SearchInputStore.js

export default {
  namespaced:true,
  state: {
    searchContent:""
  },
  getters:{
    getSearchContent(state,getters,rootState,rootGetters){
      /**
       * state 表明了当前模块的state
       * getters 表明了当前模块的getters
       * rootState 表明了根Store的state,即index.js的Store,但也包含它的子Store,咱们能够经过rootState.searchInputStore访问searchItemStore;经过rootState.rootVal访问根模块的State值。
       * rootGetters 表明了根Store的getters和它子Store的getter方法也会被挂载在rootGetters下,
       * 咱们能够经过rootGetters["searchItemStore/getHistoryList"]去访问searchItemStore模块下的getHistoryList
       * 经过rootGetters.getRootVal去访问根模块的getRootVal
       */
      //经过rootState去访问searchItemStore的State数据
      console.log(rootState.searchItemStore.searchHistoryList)
      //经过rootState去访问index.js的State数据
      console.log(rootState.rootVal)

      //经过rootGetters去访问searchItemStore的Getter
      console.log(rootGetters["searchItemStore/getHistoryList"])

      //经过rootGetters.getRootVal去访问根模块的getRootVal
      console.log(rootGetters.getRootVal)

      return state.searchContent;
    }
  },
  mutations:{
    changeSearchContent(state,payload){
      /**
       * state 表明了当前模块的state
       * payload 表明了传入的数据
       */
      //this.commit("searchItemStore/changeHistoryList",payload)调用SearchItemStore根模块的changeHistoryList
      this.commit("searchItemStore/changeHistoryList",payload)
      //经过this.commit("changeRootVal",payload)调用根模块的changeRootVal
      this.commit("changeRootVal",payload)
      console.log("changeSearchContent被调用了")
      state.searchContent=payload
    }
  },
  actions:{
    changeSearchContentByAction(context, payload){

      //调用本模块的changeSearchContent
      context.commit("changeSearchContent",payload)
      //调用本模块的otherAction
      context.dispatch("otherAction",payload)

      //调用根节点的Mutation和Action只须要传入第三个参数对象,{root:true}便可
      context.commit("changeRootVal",payload,{root:true})
      //调用根节点的changeRootValByAction
      context.dispatch("changeRootValByAction",payload,{root:true})
    },
    otherAction(context,payload){
      console.log("otherAction被调用")
    }
  }
}

复制代码

SearchItemStore

export default {
  namespaced:true,
  state: {
    searchHistoryList:["历史记录1"]
  },
  getters:{
    getHistoryList(state){
      return state.searchHistoryList;
    }
  },
  mutations:{
    changeHistoryList(state,payload){
      state.searchHistoryList.push(payload)
    }
  },
  actions:{
    changeHistoryListByAction(context,payload){
      context.commit(changeHistoryList,payload)
    }
  }
}

复制代码

咱们经过namespaced:true来对模块进行了封装。

由于SearchInputStoreSearchItemStore被封装了,咱们子组件应该如何去访问SearchInputStore呢?SearchInput又如何访问其余被封装模块和根Store的State、Getter、Mutation和Action呢?

子组件如何访问封装的模块(以访问SearchInputStore为例)

访问State

在访问被封装的State数据时,咱们只须要作以下改变**(以访问SearchInputStore的searchContent为例)**:

this.$store.state.searchContent改变成this.$store.state.searchInputStore.searchContent

访问Getter

(以访问SearchInputStore的getSearchContent为例):

this.$store.getters.getSearchContent改变成this.$store.getters["searchInputStore/getSearchContent"]

访问Mutation

(以访问SearchInputStore的changeSearchContent为例):

this.commit("changeSearchContent","新数据")改变成this.$store.commit("searchInputStore/changeSearchContent","新数据")

访问Action

(以访问SearchInputStore的changeSearchContentByAction为例):

this.dispatch("changeSearchContentByAction","新数据")改变成this.$store.dispatch("searchInputStore/changeSearchContentByAction","新数据")

封装的模块如何访问其余被封装的模块和根模块(以访问SearchItemStore为例)

先让咱们再仔细看下面的SearchInputStore的代码:

SearchInputStore

export default {
  namespaced:true,
  state: {
    searchContent:""
  },
  getters:{
    getSearchContent(state,getters,rootState,rootGetters){
      /**
       * state 表明了当前模块的state
       * getters 表明了当前模块的getters
       * rootState 表明了根Store的state,即index.js的Store,但也包含它的子Store,咱们能够经过rootState.searchInputStore访问searchItemStore;经过rootState.rootVal访问根模块的State值。
       * rootGetters 表明了根Store的getters和它子Store的getter方法也会被挂载在rootGetters下,
       * 咱们能够经过rootGetters["searchItemStore/getHistoryList"]去访问searchItemStore模块下的getHistoryList
       * 经过rootGetters.getRootVal去访问根模块的getRootVal
       */
      //经过rootState去访问searchItemStore的State数据
      console.log(rootState.searchItemStore.searchHistoryList)
      //经过rootState去访问index.js的State数据
      console.log(rootState.rootVal)

      //经过rootGetters去访问searchItemStore的Getter
      console.log(rootGetters["searchItemStore/getHistoryList"])

      //经过rootGetters.getRootVal去访问根模块的getRootVal
      console.log(rootGetters.getRootVal)

      return state.searchContent;
    }
  },
  mutations:{
    changeSearchContent(state,payload){
      /**
       * state 表明了当前模块的state
       * payload 表明了传入的数据
       */
      //this.commit("searchItemStore/changeHistoryList",payload)调用SearchItemStore根模块的changeHistoryList
      this.commit("searchItemStore/changeHistoryList",payload)
      //经过this.commit("changeRootVal",payload)调用根模块的changeRootVal
      this.commit("changeRootVal",payload)
      console.log("changeSearchContent被调用了")
      state.searchContent=payload
    }
  },
  actions:{
    changeSearchContentByAction(context, payload){

      //调用本模块的changeSearchContent
      context.commit("changeSearchContent",payload)
      //调用本模块的otherAction
      context.dispatch("otherAction",payload)

      //调用根节点的Mutation和Action只须要传入第三个参数对象,{root:true}便可
      context.commit("changeRootVal",payload,{root:true})
      //调用根节点的changeRootValByAction
      context.dispatch("changeRootValByAction",payload,{root:true})
    },
    otherAction(context,payload){
      console.log("otherAction被调用")
    }
  }
}
复制代码
访问State和Getter

先看SearchInputStore的getters:

咱们发现getSearchContent接受的参数从state变成了state,getters,rootState,rootGetters,它们的含义以下:

一、state 表明了当前模块的state

二、getters 表明了当前模块的getters

三、rootState 表明了根Store的state,即index.js的Store,但也包含它的子Store,咱们能够经过rootState.searchInputStore访问searchItemStore;经过rootState.rootVal访问根模块的State值。

四、rootGetters 表明了根Store的getters和它子Store的getter方法也会被挂载在rootGetters下,咱们能够经过rootGetters["searchItemStore/getHistoryList"]去访问searchItemStore模块下的getHistoryList

访问Mutation

(以访问SearchInputStore的changeSearchContent为例):

在SearchInputStore的Mutation中能够经过:

一、this.commit("searchItemStore/changeHistoryList",payload)调用SearchItemStore根模块的changeHistoryList

二、this.commit("changeRootVal",payload)调用根模块的changeRootVal

访问Action

(以访问SearchInputStore的changeSearchContentByAction为例):

在SearchInputStore的Action中能够调用根模块的Mutation和Action,但不能调用其它封装模块的Mutation,不然会报错。

其实这也是有道理的,当咱们本模块的Mutation异步执行完毕,想要去修改其余模块的数据,只须要在本身模块的Mutation去调用其余模块的Mutation便可,没有必要再去调用其余模块的Action。

所以咱们能够在本模块中经过context.commit()cotext.dispatch()去调用本模块和根模块的Mutation和Action:

一、调用本模块的changeSearchContent:context.commit("changeSearchContent",payload)

二、 调用本模块的otherAction:context.dispatch("otherAction",payload)

三、调用根模块的Mutation和Action只须要传入第三个参数对象,{root:true}便可:context.commit("changeRootVal",payload,{root:true})

四、调用根模块的changeRootValByAction:context.dispatch("changeRootValByAction",payload,{root:true})

最后复盘

一、Vuex是数据和视图层解耦的框架

二、在单页和小项目中没有必要使用Vuex。

三、Vuex中的State就像一个全局的数据仓,里面存放着数据源。

四、Vuex中的Getter 用来在获取数据源的时候,对数据源进行必定的加工后再返回。

五、Vuex中的Mutation用来对数据仓中的数据,进行修改。Mutation只支持同步方法。

六、Vuex中的Action和Mutation相似,他们之处在于:一、Action 提交的是 mutation,而不是直接变动状态。二、Action 能够包含任意异步操做。

七、Vuex中的Module能够将Store模块化,而后经过Module整合在一块儿。

八、关于...mapGetters、...mapMutation、...mapActions具体不展开,主要是经过es6的语法简化代码书写,能够参考官方文档: Vuex官方文档

九、看完本教程,因为内容较多,建议本身再看一次官方文档,并本身实现一个小Demo

我是大麦,若是喜欢个人文章,请给我一颗当心心。

相关文章
相关标签/搜索