Vuex 入门教程

这里要完成的功能是通过按钮的加减来动态的处理数据

我们新建一个基本的 Vue 项目

vue init webpack-simple vuex-1

运行如下命令安装相应的依赖和Vuex

npm i
npm i vuex --save

安装完之后我们来新建一个 store 文件夹,在该文件夹下面新建一个 store.js 文件,并显式的通过 Vue.use 来安装 Vuex,其代码如下:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

src目录下新建components目录,再在该目录下新建一个组件,取名为 Count.vue,其初始化代码为:

<template>
  <div>
  </div>
</template>
<script></script>

我们再在main.js文件中引入上面的store.jsCount.vue,代码如下:

import Vue from 'vue'
import Count from './components/Count.vue'

import storeConfig from './store/store'

new Vue({
  el: '#app',
  render: h => h(Count),
  storeConfig,
  template: `<Count/>`,
  comments: { Count }
})

以上就完成了一个基本结构的搭建,接下来我们来处理相应的基本功能


先完成一个现实数据的功能
首先我们在store.js文件中加入如下代码,其中 count 为我们待加减的数据:

const state = {
    count: 0
};
var vuexStore = new Vuex.Store({
    state
});

// 使用 export default 封装,让外部可以访问
export default vuexStore;

然后再在我们的 Count.vue文件中加入如下代码来显示上面的count的值

<template>
  <div>
    <div>{{$store.state.count}}</div>
  </div>

</template>
<script>
import store from "../store/store.js";
export default {
  store
};
</script>

这样子的话我们运行我们的程序,页面上就会现实count的初始值0了。

接下来我们就来实现一个加减count值的功能
首先我们来自定义两个组件:展示数据和操作按钮

Count.vue中的代码就变为:

<template>
  <div>
    <result></result>
    <opbutton></opbutton>
  </div>
</template>
<script>
import store from "../store/store.js";
export default {
  store,
  components: {
    result: {
      template: `<div>{{$store.state.count}}</div>`
    },
    opbutton: {
      template: `
      <div>
        <input type="button" value="+" @click="$store.commit('add')"/>
        <input type="button" value="-" @click="$store.commit('mul')"/>
      </div>
      `
    }
  }
};
</script>

我们看到上面的模板中的按钮点击会相应相应的方法,这个方法就是mutations中的方法,需要在store.js中声明

我们在store.js中加入如下代码:

const mutations = {
    add(state) {
        state.count++;
    },
    mul(state) {
        state.count--;
    }
};

var vuexStore = new Vuex.Store({
    state,
    // 添加 mutations
    mutations
});

以上我们就实现了一个简单的加减的功能。


我们如何在Vue组件中获取Vuex的状态值?

  • 通过computed属性直接给对象赋值

比如我们现在想实现的功能是每次点击”+”号并不是加一,我们希望它再加一之后再乘3输出
我们只要把result中的代码改为

    result: {
      template: `<div>{{count}}</div>`,
      computed: {
        count() {
          return this.$store.state.count * 3;
        }
      }
    }
  • 通过 mapState辅助函数

result中的代码如下:

    result: {
      template: `<div>{{count}}</div>`,
      computed: mapState({
        count: state => state.count * 3 //理解为传入state对象,修改state.count属性
      })
    }

当映射的计算属性的名称与state子节点名称相同的时候,可以使用mapState传递一个数组
如上面例子中的计算属性为countstate子节点名称相同,所以可以 映射 this.countstore.state.count

如下代码:

    result: {
      template: `<div>{{count}}</div>`,
      computed: mapState(['count'])
    }

上面代码中我们按钮的代码如下

<input type="button" value="+" @click="$store.commit('add')"/>

如果我们希望能够传递一个参数给 mutation中的方法要怎么做呢?比如说每次都是加3

则上面的代码改为:

<input type="button" value="+" @click="$store.commit('add',3)"/>

则对应的store.js文件中mutation中的add方法只需要添加一个参数即可,如下:

    add(state,n) {
        state.count+=n;
    }

这种向store.commit 传入额外的参数的行为我们称为 ——mutation 的 提交载荷(payload)

在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读:
如上代码可以改为

<input type="button" value="+" @click="$store.commit('add',{num:3})"/>

    add(state,obj) {
        state.count+=obj.num;
    }

有的时候我们并不是很想都看到例如@click="$store.commit('add')"这样子的代码,而是想使用直接一个字符串代替,如@click="add"

那么首先我们要像引入mapState一样来引入mapMutations,如下代码

import { mapState,mapMutations } from "vuex";

然后我们就可以添加methods属性并加入mapMutations,如下

    opbutton: {
      template: `
      <div>
        <input type="button" value="+" @click="add"/>
        <input type="button" value="-" @click="mul"/>
      </div>
      `,
      methods:mapMutations ([
          'add',
          'mul'
        ])
    }

有时候我们希望在获取数据之前对数据进行一些操作,即对数据进行一层过滤和加工
比如在上面的例子的基础上,我们希望每次在进行加减运算之前,都将count的值增加100
则我们在store.js文件中加入如下代码

const getters = {
    count: function (state) {
        return state.count += 100;
    }
}

var vuexStore = new Vuex.Store({
    state,
    mutations,
    getters
});

在我们的 Count.vue中的代码如下

    result: {
      template: `<div>{{count}}</div>`,
      computed: {
        count() {
          return this.$store.getters.count;
        }
      }
    },

接下来我们使用mapGetter来简化我们模板中的代码

首先导入mapGetter

import { mapState, mapMutations,mapGetters } from "vuex";

则相应的计算属性中的代码可以简化为:

    result: {
      template: `<div>{{count}}</div>`,
      computed: {
        ...mapGetters(["count"])
      }
    }

Action 类似于 mutation,不同在于:

Action是异步改变state的状态,而mutation是同步。
Action里面是可以调用Mutation里面的方法的。

如下,我们来声明一个Action,里面加上两个方法分别调用mutation里面的两个加减方法。

const actions = {
    addAction(context) {
        context.commit('add');
    },
    mulAction(context) {
        context.commit('mul');
    }
};
var vuexStore = new Vuex.Store({
    state,
    mutations,
    getters,
    actions
});

相应的Count.vue里面引入mapActions,相应的代码变为

<script>
import store from "../store/store.js";
import { mapState, mapMutations, mapGetters, mapActions } from "vuex";

export default {
  store,
  components: {
    result: {
      template: `<div>{{count}}</div>`,
      computed: {
        ...mapGetters(["count"])
      }
    },
    opbutton: {
      template: `
      <div>
        <input type="button" value="+" @click="addAction"/>
        <input type="button" value="-" @click="mulAction"/>
      </div>
      `,
      methods: {
        ...mapMutations(["add", "mul"]),
        ...mapActions(["addAction", "mulAction"])
      }
    }
  }
};
</script>

那要怎么来验证Action是异步执行的呢?

我们在addAction中添加如下代码

const actions = {
    addAction(context) {
        setTimeout(() => { context.commit('add') }, 3000);
        console.log('我提前执行了');
    },

查看控制台就会发现,console.log('我提前执行了');会首先打印出来。


当应用变得非常复杂时,store 对象就有可能变得相当臃肿,所以这个时候我们就需要把我们状态的各种操作进行一个分模块,分模块后再进行按模块编写。这就用到 module —— 状态管理器的模块组操作。
每个模块拥有自己的 state、mutation、action、getter甚至是嵌套子模块——从上至下进行同样方式的分割

store.js文件中,修改为如下代码:、


const moduleA = {
    state,
    mutations,
    getters,
    actions
}
var vuexStore = new Vuex.Store({
    modules :{a:moduleA}
});

现在我们要在模板中使用count的状态值,则如下

<div>{{$store.state.a.count}}</div>

或者使用计算属性

    result: {
      template: `<div>{{count}}</div>`,
      computed: {
        count() {
          return this.$store.state.a.count;
        }
      }
    },

猜你喜欢

转载自blog.csdn.net/zjq_1314520/article/details/79539966