Vuex入门教程

【Vue】-- Vuex简单入门教程 ​ 简单来说,Vuex就是一个状态机,采用集中式存储帮助我们管理所有组件的共享状态,可以用来解决多组件数据通信,可以把vuex理解成一个仓库,假设有A、B两个组件需要通信传值,那么可以把A组件和B组件的数据放到Vuex中, A组件想要获取B组件数据从vuex中拿 B组件想要获取A组件的数据从Vuex拿。 ​ 阅读详情

前言

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

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

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

为什么有EventBus还要使用Vuex

为什么我们有EventBus了,还要使用Vuex?

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

对于Vuex是什么,我的理解是:

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

而已经有EventBus我们为什么还要使用Vuex这个问题上,我的理解是:

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

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

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

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

子组件文件名:SearchInput.vue和SearchItem.vue

父组件文件名:StateView.vue

目录结构展示:

1、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对象。

查看我们的目录结构:

1、创建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({
})
2、在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.js和SearchInput.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的感受结论:

1、state是一个数据存储的仓库,所有的数据源都会存放在这里,就类似组件中的data。

2、我们可以明显感觉到,我们在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的感受结论

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

2、与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中的方法,它接收两个参数:

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

控制台输出的结果

Mutation的感受结论:

1、通过Mutation我们可以对数据仓中的数据进行修改,我们可以在组建中通过调用this.$store.commit()方法去调用对应的Mutation去修改数据。

2、Mutation中只能执行同步的方法,如果需要执行异步方法,我们要使用接下来即将登场的Action。

Action

Action和Mutation类似,他们之处在于:1、Action 提交的是 mutation,而不是直接变更状态。2、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,该函数接收两个参数:
1、Store中Action对应的方法名
2、要传递的数据

* 控制台输出结果*

Action的感受结论:

1、Action和Mutation类似,它只是能够处理异步的情况,最终通过commit()函数调用Mutation去修改数据。

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

Module

可以将Store模块化,然后通过Module整合在一起。

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

这时候,我们希望把Store模块化,例如不同子组件的数据抽取出来写成单独的一个Store。

这时候我们就需要通过Module整合各个模块,然后在将Store挂在在根组件下。

现在我们不再以SearchStore举例了,我们创建3个新的Store文件:

1、index.js Store,主要负责整合所有的Store模块。

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

3、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.js和SearchItemStore.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.js和SearchItemStore.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.js、SearchInputStore.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来对模块进行了封装。

因为SearchInputStore和SearchItemStore被封装了,我们子组件应该如何去访问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,它们的含义如下:

1、state 代表了当前模块的state

2、getters 代表了当前模块的getters

3、rootState 代表了根Store的state,即index.js的Store,但也包含它的子Store,我们可以通过rootState.searchInputStore访问searchItemStore;通过rootState.rootVal访问根模块的State值。

4、rootGetters 代表了根Store的getters和它子Store的getter方法也会被挂载在rootGetters下,我们可以通过rootGetters[“searchItemStore/getHistoryList”]去访问searchItemStore模块下的getHistoryList

访问Mutation

(以访问SearchInputStore的changeSearchContent为例):

在SearchInputStore的Mutation中可以通过:

1、this.commit(“searchItemStore/changeHistoryList”,payload)调用SearchItemStore根模块的changeHistoryList

2、this.commit(“changeRootVal”,payload)调用根模块的changeRootVal

访问Action

(以访问SearchInputStore的changeSearchContentByAction为例):

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

其实这也是有道理的,当我们本模块的Mutation异步执行完毕,想要去修改其他模块的数据,只需要在自己模块的Mutation去调用其他模块的Mutation即可,没有必要再去调用其他模块的Action。

因此我们可以在本模块中通过context.commit()和cotext.dispatch()去调用本模块和根模块的Mutation和Action:

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

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

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

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

最后复盘

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

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

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

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

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

6、Vuex中的Action和Mutation类似,他们之处在于:1、Action 提交的是 mutation,而不是直接变更状态。2、Action 可以包含任意异步操作。

7、Vuex中的Module可以将Store模块化,然后通过Module整合在一起。

8、关于…mapGetters、…mapMutation、…mapActions具体不展开,主要是通过es6的语法简化代码书写,可以参考官方文档:
Vuex官方文档

9、看完本教程,由于内容较多,建议自己再看一次官方文档,并自己实现一个小Demo

我是大麦,如果喜欢我的文章,请给我一颗小心心。

vuex的入门教程 vuex的结构 vuex官网 基本掌握这四个即可,后续通过做项目实战进阶 开始使用 1. 创建一个vue项目 2. 安装vuex npm install vuex --save 3. 新建store目录,创建一个index.js 4. index.js中写入基本结构 import Vuex from 'vuex' import Vue from 'vue' Vue.use(Vuex) export default new Vuex.Store({ state :{}, get 阅读详情

相关推荐

Splunk CVE-2018-11409认证绕过漏洞深度解析

Splunk作为主流企业级日志分析平台,其Web管理接口的认证机制直接关系到整个安全运营体系的可信边界。CVE-2018-11409本质上是REST API路由层会话校验缺失引发的未授权访问问题,根源在于`/en-US/splunkd/__raw/`路径绕过了splunkweb与splunkd之间的信任链验证,导致配置文件、用户哈希、App源码等敏感信息明文泄露。该漏洞凸显了Web接口权限模型设计失守的风险,尤其在默认配置未加固、HTTPS未启用、初始密码未修改的生产环境中危害急剧放大。结合vulfocus

weixin_30875157的博客 598

前端写接口 请求后台数据 存vuex中 打印到控制台

前端写接口请求后台数据,ajax axios vuex 数据处理,数据渲染。

ccq的博客 4577

Halcon 3D点云匹配实战:从预处理到模板创建的完整流程(附代码)

本文详细介绍了Halcon在3D点云匹配中的实战应用,涵盖从预处理到模板创建的完整流程。通过代码示例和实用技巧,帮助开发者掌握点云采样、降噪、三角化等关键技术,并优化匹配参数以提高精度和效率。适用于工业检测、机器人引导等领域。

weixin_33670786的博客 433

vuex具体内容和基本使用

当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键,通常我们把 store 的 state 通过 mapState 函数映射到组件的 computed 上。

m0_60970928的博客 420

ThinkAdmin后台Getshell

通过文件包含或者图片马的方式Getshell。修改其可允许的文件类型,php不允许,可添加。系统管理->系统参数配置->本地服务器存储。

hot_milk1的博客 1864

iverilog+GTKwave使用总结

iverilog是一个开源的硬件描述语言(HDL)仿真工具,用于对硬件描述语言(如Verilog)编写的数字电路进行仿真。它可以将Verilog代码编译为仿真模型,并通过仿真运行来验证设计的正确性。iverilog支持IEEE 1364-2005 Verilog语言标准,并提供了丰富的功能,包括对多种Verilog语言特性的支持、模块化设计、测试平台等。它还可以与其他工具(如GTKWave波形查看器)配合使用,以便进行仿真后的波形查看和分析。

争取早日成为硅农 2万+

解决vue不相关组件之间的数据传递----vuex的学习笔记,解决报错this.$store.commit is not a function...

Vue的项目中,如果项目简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式 进行传递 但是如果是大中型项目中,很多时候都需要在不相关的平行组件之间传递数据,并且很多数据需要多个组件循环使用。这时候再使用上面的方法会让项目代码变得冗长,并且不利于组件的复用,提高了耦合度。 Vue 的状态管理工具 Vuex 完美的解决了这个问题。 看了下vuex的官网,觉得...

weixin_30908103的博客 2235

IDM 的免费替代品来了!这款开源下载器速度提升500%

💡分享一款开源的下载管理工具,支持多线程加速(最高提升500%)、队列管理、计划任务和浏览器集成,界面现代化且支持深色模式,跨平台支持Windows/Linux,是IDM的优秀替代方案🎈

XiaoqiangClub的博客 730

Vue状态管理插件-Vuex入门

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 Vuex是在组件外部管理状态,是用来管理组件之间通信的一个插件。这里的状态就是指数据。

dreamingbaobei的博客 908

利用 IP 中的集成调试功能来调试 PCI Express 链接训练问题

JTAG Debugger”和“In-system IBERT”功能结合在一起即可提供即时信息,用于判断链接训练问题的可能原因。“test_rd.tcl”文件可读取 BRAM 中存储的调试数据,并输出 *.dat 文件,如下所示。同样,您可能看到某一箭头旁的数字较大,表明可能存在不稳定的链接。要采集 PCIe 链接眼图,请在 IP 配置 GUI 的“Add. Debug Options”选项卡中选择“启用 In-System IBERT (Enable In-System IBERT)”选项。

qq_43416206的博客 534

Android一个APP里面最少有几个线程

Android应用启动时,默认会创建一个进程,该进程中最少包含负责处理用户交互、UI更新等核心操作,所有与界面相关的逻辑必须在此线程执行。若在此线程执行耗时操作(如网络请求),会导致界面卡顿甚至触发ANR(应用无响应)。当对象重写了finalize()方法时,该线程负责将这些对象放入队列并调用其finalize()方法,完成资源释放后再由GC回收。监控的执行效率。如果finalize()方法执行超时(默认10秒),此线程会触发虚拟机退出以防止应用长时间阻塞。

编程进化论 613

vuex入门教程

vuex入门教程 参考网址: https://mp.weixin.qq.com/s/rs2xAvsY8SYtrMchz88dlQ 说明 vuex 对于 vue 来说 , 也是很重要的组件 , 但是项目是否使用 vuex 看情况而定 , 不是为了使用 vuex 而使用 vuex vuex , vue-router , axios 基本都是 vue-cli 中必不可少的组件 , 加上 UI 组件 element-ui , 基本就可以完成一个简单的项目了 这篇文章很好的介绍了 vuex 的使用 , 通俗易懂

java技术博客 728

YOLOv11涨点改进 | 全网独家创新,损失函数改进篇 | TGRS 2025 | 引入AdaFocalLoss损失函数,改进小目标检测,自适应聚焦小目标与样本分布不平衡,提升检测精度与训练稳定性

本文提出了一种改进YOLOv11模型的AdaFocalLoss损失函数,通过动态调节机制有效提升小目标检测性能。AdaFocalLoss融合了目标尺寸感知和IoU引导的自适应调节,解决了传统损失函数在小目标检测中的样本不平衡问题。该方法自动调整训练权重,无需手动调参,显著提升了模型在多尺度目标、复杂背景下的检测精度和训练稳定性。实验表明,AdaFocalLoss能更好地平衡不同尺度目标的梯度分布,改善边界完整性,减少误检漏检。文章详细介绍了算法原理、实现代码和在YOLOv11中的集成方法,为提升目标检测性能

Ai缝合怪、助力小伙伴高效发论文 335

Vuex 入门教程

这里要完成的功能是通过按钮的加减来动态的处理数据 我们新建一个基本的 Vue 项目 vue init webpack-simple vuex-1 运行如下命令安装相应的依赖和Vuex npm i npm i vuex --save 安装完之后我们来新建一个 store 文件夹,在该文件夹下面新建一个 store.js 文件,并显式的通过 Vue.use 来安装 Vuex,其代码如...

未思 2456

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Vuex入门教程(详细篇)

目录1.Vuex是什么2.Vuex的使用3.Vuex的核心概念3.1 State3.1.1创建数据3.1.2访问数据的第一种方式3.1.3访问数据的第二种方式3.1.4组件代码与效果图3.2 Mutation3.2.1定义Mutation3.2.2 触发Mutation的第一种方式3.2.3定义Mutation(带参数)3.2.3 触发Mutation的第二种方式3.2.4 组件代码与效果图3.3 Action3.3.1定义Action3.3.2 触发Action的第一种方式3.3.3 定义Action(带

摸鱼程序员 3351

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Vuex的入门教程

前言 在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式,详细点击这篇文章查看。 但是如果是大型项目,很多时候都需要在子组件之间传递数据,使用之前的方式就不太方便。Vue 的状态管理工具 Vuex 完美的解决了这个问题。 一、安装并引入 Vuex 项目结构: 首先使用 npm 安装 Vuex ? ...

weixin_30294709的博客 123

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Vuex入门教程快速入门简介

Vuex入门教程快速入门简介 文章目录Vuex入门教程快速入门简介什么是VuexVuex可以干什么工作流程核心概念安装全局初始化多模块StoreState单一状态树Getter计算属性Mutation更改状态Actions发起动作从vuex3到vuex4其他文档其他参考资料 什么是Vuex Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 他相当于Vue的共享数据层 / 共享内存,当你需要开发业务涉及到数据需要跨页面,跨组件时,使用Vuex比使用参数传递,要方便得多。 可以说,当你需要开发一

Nicker_的专栏 289

VUEX入门教程

首先,新建一个vue项目,在命令行中使用:vue init webpack web 然后,安装vuex,使用命令:npm install vuex --save 出现以下代码提示显示安装成功: 首先,我们在src目录下新建文件夹 store,在当前文件夹中新建文件index.js 在当前的index.js文件中,我们在文件中引用入ue和vuex,在vue中注册vuex,创建vuex.Stor...

weixin_43989275的博客 450

详细的Vuex入门教程

  什么是Vuex? vuex是一个专门为vue.js设计的集中式状态管理架构。状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态。简单的说就是data中需要共用的属性。 引入Vuex(前提是已经用Vue脚手架工具构建好项目) 1、利用npm包管理工具,进行安装 vuex。在控制命令行中输入下边的命令就可以了。  npm install vuex -...

lotte 476
上一篇: [JS]JavaScript一张图引发的深思
VikcyWinner
博客等级 码龄11年 12粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值