Vuejs全家桶系列 --- Vuex

简介

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说,用来集中管理数据,类似于React中的Redux,都是基于Flux的前端状态管理框架

基本用法

以官方例子为例:
当点击+1按钮的时候,count 加1,点击-1按钮的时候,count 减1.

安装vuex
cnpm install vuex -S
创建store.js文件,在main.js中导入并配置store.选项
import store from './store.js'

new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})
编辑store.js文件
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

//数据
var state = {
    count: 10
}

//获取数据
var getters = {
    count(state){
        return state.count;
    }
}

//异步动作
const actions = {
    add({commit,state}){
        commit('add');
    },
    sub({commit,state}){
        commit('sub');
    }   
}

//同步动作
const mutations = {
    add(state){
        state.count++;
    },
    sub(state){
        state.count--;
    }
}

const store = new Vuex.Store({
    state,
    getters,
    actions,
    mutations
})

export default store;
Vuex的核心是Store(仓库),相当于是一个容器,一个store实例中包含以下属性的方法:
    state       定义属性(状态、数据)
    getters     用来获取属性
    actions     定义方法(动作)
    commit      提交变化,修改数据的唯一方式就是显式的提交mutations
    mutations   定义变化
    注:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化 
编辑App.vue

在子组件中访问store对象的两种方式:

  1. 通过this.$store访问
  2. 通过mapState、mapGetters、mapActions访问

        mapState    获取state
        mapGetters  获取getters
        mapActions  获取actions
    
<template>
  <div id="app">
    <p>{{count}}</p>
    <button @click="add">+</button>
    <button @click="sub">-</button>
  </div>
</template>

<script>
import {mapGetters,mapActions} from 'vuex'
export default {
  name: 'app',
  data() {
     return {

     }
  },
  // computed:{ //方式一
  //     count(){
  //        return this.$store.state.count;
  //     }
  // },
  computed:{
      ...mapGetters([
        'count'
      ]),
      msg(){
          console.log("同时使用mapGetters和自定义computed");
      }
  },
  //computed:mapGetters([
  //        'count'
  //]),
  methods:mapActions([
        'add',
        'sub'
  ])
}
</script>

<style>
  a {
    text-decoration: none;
  }
</style>

探究

我们再看一张图


很多人会疑惑:
为什么要有actions和mutations?
我为什么要在action里调用mutations然后由mutations去修改state?
为什么不可以在mutations里直接去修改state?
官方的说法是:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化
我们也经常听到actions是异步动作,mutations是同步动作,那么该怎么去理解呢?

我举一个例子,也许你就会豁然开朗!
假如你是一个君王,前方正在打仗。每隔一段时间前线就来一个探子汇报战况:
“报!!! 我们还有1500军队,弟兄们快顶不住了!!”

这就是getters的作用了

<span>我军军队:{{count}}</span>

computed:mapGetters([
        'count'
  ]),

var getters = {
    count(state){
        return state.count;
    }
}

于是你慌了,你命令道:
“不行,赶快撤军,速度跑路!!”

<button @click="chejun">撤军</button>

methods: {
     chejun(){
        this.$store.dispatch("chejun");
      }
}

于是探子把你的命令传给了前线元帅。
元帅看到你的圣旨上两个大字:“撤军”
他会怎么做?会立马撤军吗?
不会吧,他要进行各方面的准备和筹划吧!**
这就是actions的作用了

//异步动作 进行逻辑判断,异步请求,错误处理
const actions = {
    chejun({commit,state}){
        console.log("今晚开始撤军!!");
        if(state.count >= 10000){
            console.log("赵四你带3000人掩护");
        },
        else if(state.count >= 5000){
            console.log("赵四你带500人掩护");
        },
        else if(state.count >= 1000){
            console.log("赵四你带50人摆空城记");
        }
        console.log("其他人随我出城!!");
        commit('chejun');
    }
}

元帅的命令下来了以后,士兵们执行就好了
这就是matations的作用了

//同步动作 立马就去执行
const mutations = {
    chejun(state){
        state.count = 0;
    }
}

例子虽然不太恰当,但是你应该明白为什么要有actions和mutations了吧。为什么叫actions异步,mutations同步了吧。

进阶

明白了vuex的基本用法和逻辑结构后,我们再探讨下vuex的项目结构

项目结构

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。
  2. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  3. 异步逻辑都应该封装到 action 里面

只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。

对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:

├── index.html
├── main.js
├── api
│   └── ... # 抽取出API请求
├── components
│   ├── App.vue
│   └── ...
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块

我们把上面的例子改进一下
这是项目结构图

子模块

user.js

/**
 * 用户模块
 */

import types from '../types.js' //从types.js中引用常量

 const state={
    count:6
 }

var getters={
    count(state){
        return state.count;
    }
}

const actions = {
    increment({commit,state}){
        commit(types.INCREMENT); //提交一个名为increment的变化,名称可自定义,可以认为是类型名
    },
    decrement({commit,state}){
        if(state.count>10){
            commit(types.DECREMENT);
        }
    }
}

const mutations={
    [types.INCREMENT](state){
        state.count++;
    },
    [types.DECREMENT](state){ //es6语法:[]内的视为常量
        state.count--;
    }
}

export default {
    state,
    getters,
    actions,
    mutations
}

公共actions

actions.js


import types from './types.js'

const actions={
    incrementAsync({commit,state}){
        //异步操作
        var p=new Promise((resolve,reject) => {
            setTimeout(() => {
                resolve();
            },3000);
        });

        p.then(() => {
            commit(types.INCREMENT);
        }).catch(() => {
            console.log('异步操作');
        });
    }
}

export default actions;

公共getters

getters.js

const getters={
    isEvenOrOdd(state){
        return state.user.count%2==0?'偶数':'奇数';
    }
}

export default getters;

常量模块

type.js

/**
 * 定义类型常量
 */

const INCREMENT='INCREMENT'
const DECREMENT='DECREMENT'

export default {
    INCREMENT,
    DECREMENT
}

根模块

index.js

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

Vue.use(Vuex);

import getters from './getters.js'
import actions from './actions.js'
import user from './modules/user.js'

export default new Vuex.Store({
    getters,
    actions,
    modules:{  //这里存放的是子模块
        user
    }
});
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值