Vue核心特性之Vuex用法 一篇足矣

文章目录

      • 1. Vuex概念和作用解析
        • 1.1Vuex概念
        • 1.2 作用解析
      • 2.单界面到多界面状态管理切换
        • 2.1 单界面状态管理切换
        • 2.2 Vuex的安装以及使用
      • 3. Vuex-devtools的安装
      • 4. 举例查看Vuex是否跟踪记录
      • 5.Vuex五大核心
        • 5.1 vuex-state
          • 5.1.1Vuex-state单一状态树
        • 5.2 vuex-getters
          • 5.2.1 默认第一个参数state
          • 5.2.2 默认第二个参数getters
          • 5.2.3 传入普通参数
        • 5.3 Vuex-mutations
          • 5.3.1 不携带参数
          • 5.3.2 携带参数
          • 5.3.3 mutations的特殊提交风格
        • 5.4 Vuex-actions(异步函数在此操作)
        • 5.5 Vuex-modules
      • 6. Vuex中的目录组织

1. Vuex概念和作用解析

1.1Vuex概念

官方解释:Vuex是一个专为Vue.js应用程序开发的状态管理模式。

  • 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保存状态以一种可预测的方式发生变化。
  • Vuex也集成到Vue的官方调试工具devtools extension,提供了诸如零配置的time-travel调试、状态快照导入导出等高级调试功能。

个人理解:状态管理

  • 状态管理模式、集中式存储管理这些名词听起来就非常高大上,让人难以理解。
  • 其实,你可以简单的将其看成把需要多个组件共享的变量全部存储在一个对象里。
  • 然后,将这个对象放在顶层的Vue实例中,让其它组件可以使用。
  • 那么,多个组件是不是就可以共享这个对象中的所有变量属性了呢?

如果这样的话,为什么官方还要专门出一个插件Vuex呢?难道我们不能自己封装一个对象来管理吗?

  • 当然可以自己封装一个对象来管理,但是VueJS带给我们最大的遍历是响应式
  • 如果你自己封装一个对象能不能保证里面所有的属性做到响应式呢?当然可以,只是自己封装的稍微麻烦一些。
  • 不用怀疑,Vuex就是为了提供这样一个在多个组件间共享状态的插件,我们直接使用即可,不用自己写一个。

假如我们自己封装一个对象,如何封装的?

const sharedObj={
     
	name:"haha",
	age:18
}
Vue.prototype.sharedObj=sharedObj;//使用Vue原型,这就可以在其它组件共享使用

//在其它组件可以直接这样用
this.sharedObj.name来使用这对象的属性

注意:这样实现的对象只能在组件共享,还不能做到响应式。这里就不再做多讨论,重点是学习Vuex。

1.2 作用解析

有什么状态是需要我们在多个组件间共享的呢?

  • 如果做过大型项目,你一定遇到过多个状态,在多个页面间共享的问题。
  • 比如用户的登录状态、用户名称、头像、地理位置信息等。
  • 比如商品的收藏、购物车的物品等。
  • 这些状态信息,我们都可以统一放在一个地方,对它进行保存和管理,而且它们还是响应式的。

2.单界面到多界面状态管理切换

2.1 单界面状态管理切换

我们知道,要在单个组件中进行状态管理是一件非常简单的事情。
Vue核心特性之Vuex用法 一篇足矣_第1张图片

这图片中的三种东西怎么理解呢?

  • State:即状态(你可以把它当成组件data中的属性)
  • View:视图层,可以针对State的变化,显示不同的信息。
  • Actions:这里的Actions主要是用户的各种操作:点击、输入等,会导致状态的变化。

下面一个简单的实例:

<template>
  <div id="app">
    <h3>{
    {count}}h3>
    <button @click="add">+button>
    <button @click="sub">-button>
  div>
template>

<script>
// import Home from "./components/Home.vue";
export default {
      
  name: "App",
  data: function () {
      
    return {
      
      count: 0,
    };
  },
  methods: {
      
    add: function () {
      
      this.count++;
    },
    sub: function () {
      
      this.count--;
    },
  },
};
script>

<style>
style>

Vue核心特性之Vuex用法 一篇足矣_第2张图片
看到上面的动图,你即可以将:

  • count变量当成State
  • 按钮的点击事件当作Actions
  • 在页面上0、1、2的切换即是针对count的变化,显示不同的内容。

2.2 Vuex的安装以及使用

当在多个页面想要实现共享时,我们会使用Vuex插件,既然它是一个插件,那么它需要下载安装:

npm install vuex --save

这个插件与vue-router插件都是Vue中非常重要的,vue-router在项目中有一个专门的router文件夹管理着路由相关的内容。因此,这里我们也在项目的src文件下创建一个名为store的文件夹并添加index.js文件,方便管理。
Vue核心特性之Vuex用法 一篇足矣_第3张图片
看看官方的Vuex状态管理图例:(该图是学习重点,务必记住)
Vue核心特性之Vuex用法 一篇足矣_第4张图片

图例解释:

  • 在组件中使用dispatch()将交互派遣给Actions。
  • 通常Actions只用于处理异步(网络请求等)。
  • 若没有异步则组件可以直接使用commit()提交到Mutations。
  • 注意:Devtools是帮我们记录状态的,所以务必要经过Mutations这一步,否则无法跟踪记录。

实例:在多组间使用Vuex共享的数据:

下面开始使用Vuex插件:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
  	counter:999
},
  mutations: {
     },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

这是一个比较固定的模板,Vuex实例中的属性基本我们都要用到。然后我们在Vue实例处引入Vuex实例并使用即可。

对象中属性解释:

  • state相当于组件的data属性
  • mutations相当于methods属性
  • actions则只有在使用异步时才使用
  • getters相当于组件的computed属性

在Vue实例中引用Vuex实例:

//main.js
import Vue from "vue";
import App from "./App";
import store from "./store/index";
Vue.config.productionTip = false;

new Vue({
     
  el: "#app",
  store,
  render: h => h(App)
});

在App.vue和Home.vue组件使用Vuex共享的数据:

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>我在App.vue组件使用counter: {
     {
      $store.state.counter }}</h3>
    <Home></Home>
  </div>
</template>

<script>
import Home from "./components/Home.vue";
export default {
     
  name: "App",
  components: {
     
    Home
  }
};
</script>

<style></style>

Home.vue:

<template>
  <div>
    <hr />
    <h2>我是App.vue的子组件</h2>
    <h2>我在Home.vue组件中使用counter:{
     {
      $store.state.counter }}</h2>
  </div>
</template>

<script>
export default {
     };
</script>

<style></style>

运行:
Vue核心特性之Vuex用法 一篇足矣_第5张图片
上面两个组件是父子关系。他们都使用了Vuex中共享的counter。

注意:

  • $store对象就是我们在store/index.js中创建的Vuex实例,使用跟普通对象一样。

3. Vuex-devtools的安装

(前提是你能使用外国网络,即)
首先我们在chorme浏览器中:

  • 打开设置
  • 左下角点击“扩展程序”
  • 搜索devtools
  • 找到Vue.js的devtools添加扩展
  • 重启浏览器,打开检查

Vue核心特性之Vuex用法 一篇足矣_第6张图片
上面多了一个Vue,点开即可使用该扩展。

4. 举例查看Vuex是否跟踪记录

这个实例由于没有用到异步操作,所以直接从Component–>Mutations–>State,跳过Actions。这是一个点击按钮实现数字增减的实例。

Store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 999
  },
  mutations: {
     
    add(state) {
     
      state.counter++;
    },
    sub(state) {
     
      state.counter--;
    }
  },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

上面说过,Mutations相当于组件的methods属性。这里定义了两个方法,让两个组件调用共享。

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>我在App.vue组件使用counter: {
     {
      $store.state.counter }}</h3>
    <Home></Home>
  </div>
</template>

<script>
import Home from "./components/Home.vue";
export default {
     
  name: "App",
  components: {
     
    Home
  }
};
</script>

<style></style>

Home.vue:(重点)

<template>
  <div>
    <hr />
    <h2>我是App.vue的子组件</h2>
    <h3>我在Home.vue组件中使用counter:{
     {
      $store.state.counter }}</h3>
    <button @click="addition">+</button>
    <button @click="$store.commit('sub')">-</button>
  </div>
</template>

<script>
export default {
     
  methods: {
     
    addition: function () {
     
      this.$store.commit("add");
    },
  },
};
</script>

<style></style>

这里我使用了两种方式调用Vuex中mutations中的方法,就是为了说明这两种方法都可以使用。

下面是案例运行图:
Vue核心特性之Vuex用法 一篇足矣_第7张图片
看到Vuex的记录了吧,每点击一次按钮都会记录相应的状态。

5.Vuex五大核心

5.1 vuex-state

在上面我已经说过:state是类似于组件中的data属性,用于定义在各个组件共享的数据。

下面举例使用:

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 999,
    fruits: ["苹果", "火龙果", "百香果", "无敌果"]
  },
  mutations: {
     },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>我在App.vue组件使用counter: {
     {
      $store.state.counter }}</h3>
    <ul>
      <li v-for="fruit in $store.state.fruits">{
     {
     fruit}}</li>
    </ul>
  </div>
</template>

<script>
export default {
     
  name: "App",
};
</script>

<style></style>

上面我在store/index.js中的state属性定义了数据,然后到根组件App.vue使用数据,这里我就不再使用多组件了,在其它组件用法是一样的。
Vue核心特性之Vuex用法 一篇足矣_第8张图片

5.1.1Vuex-state单一状态树

什么是单一状态树?

  • 英文名称是Single Source of Truth,也可以翻译成单一数据源。

但是,它是什么呢?举一个生活中的例子:

  • 我们知道,在国内我们有很对信息需要被记录,比如上学的个人档案、工作后的社保记录、公积金记录以及其它相关的户口、医疗、文凭、房产记录等等/
  • 这些信息被分布在很多地方进行管理,有一天你需要办某个业务时,你需要到各个相应部门去打印、盖章各种资料,最后到一个地方提交你的所有信息。
  • 这种保存信息的方案,不仅仅低效,而且不方便管理,以及日后的维护。

这个和我们在应用开发比较类似:

  • 如果状态信息是保存在多个Store对象中,那么之后的管理和维护就会变得困难。
  • 所以Vuex也使用单一状态树来管理应用层级的全部状态。
  • 即就是一个项目只有一个Vuex实例对象store。

5.2 vuex-getters

getters类似于组件的computed计算属性。

什么时候使用计算属性呢?

当在state定义一些数据时,如果数据是直接可以使用的话,那就可以直接使用$store.state来使用;如果数据还需进行一些处理才可以使用的话,那么就用到getters属性。

注意:getters属性中定义的的函数的参数问题

  • 参数一:默认是state
  • 参数二:默认是getters
  • 如果想要传入其它参数,则需返回一个函数
5.2.1 默认第一个参数state

下面举个例子:将数据过滤得到想要的数据

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50,
    people: [
      {
     
        name: "张三",
        age: 18
      },
      {
     
        name: "张si",
        age: 25
      },
      {
     
        name: "张wu",
        age: 35
      },
      {
     
        name: "张liu",
        age: 45
      }
    ]
  },
  mutations: {
     },
  actions: {
     },
  getters: {
     
    Filter: function(state) {
     
      return state.people.filter(man => man.age >= 20);
    }
  },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <ul>
      <li v-for="man in $store.getters.Filter">{
     {
     man}}</li>
    </ul>
  </div>
</template>

<script>
export default {
     
  name: "App",
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第9张图片
我们只获取年龄大于20岁的人的信息。

5.2.2 默认第二个参数getters

即如果一个getters中的函数也想使用getters中的另一个函数,那该怎么使用呢?

第二个参数使用getters

实例:

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50,
    people: [
      {
     
        name: "张三",
        age: 18
      },
      {
     
        name: "张si",
        age: 25
      },
      {
     
        name: "张wu",
        age: 35
      },
      {
     
        name: "张liu",
        age: 45
      }
    ]
  },
  mutations: {
     },
  actions: {
     },
  getters: {
     
    Filter: function(state) {
     
      return state.people.filter(man => man.age >= 20);
    },
    getLength: function(state,getters) {
     
      return getters.Filter.length;
    }
  },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

注意:getLength()的第二个参数传入getters作为函数的参数,然后使用getters.Filter调用了getters中的Filter函数,Fliter返回一个过滤后的数组,再取的长度。

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <ul>
      <li v-for="man in $store.getters.Filter">{
     {
     man}}</li>
    </ul>

    <h2>数据长度:{
     {
     $store.getters.getLength}}</h2>
  </div>
</template>

<script>
export default {
     
  name: "App",
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第10张图片

5.2.3 传入普通参数

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50,
  },
  mutations: {
     },
  actions: {
     },
  getters: {
     
    example: function(state, getters) {
     
      return function(obj) {
     
        console.log("传入的参数:", obj);
        return obj;
      };
    }
  },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>

    <h2>测试第三个参数:{
     {
     $store.getters.example({
     name:"大刀王五",hobby:["篮球","耍刀"]})}}</h2>
  </div>
</template>

<script>
export default {
     
  name: "App",
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第11张图片
当我们想给函数传入自定义参数时,就像上面一样返回一个带参数的函数即可。

5.3 Vuex-mutations

mutations是在Vuex-devtools保存状态记录的核心,如果想要让devtools记录着state数据的更新,那么唯一的方式就是提交到Mutations。

Mutations主要包括两部分:

  • 字符串的事件类型(即函数名)
  • 一个回调函数,该回调函数的第一个参数就是state

为了证实只有通过Mutations的数据才保存状态记录,下面举两个例子:一个绕过Mutations更改数据,一个通过Mutations更改数据。

5.3.1 不携带参数

实例1:通过Mutations更改:按钮点击(通过Mutations提交)

store/index.js

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50
  },
  mutations: {
     
    add: function(state) {
     
      state.counter += 5;
    },
    sub: function(state) {
     
      state.counter -= 5;
    }
  },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>counter:{
     {
     $store.state.counter}}</h3>
    <button @click="addition">+</button>
    <button @click="subtraction">-</button>
  </div>
</template>

<script>
export default {
     
  name: "App",
  methods: {
     
    addition() {
     
      this.$store.commit("add");
    },
    subtraction() {
     
      this.$store.commit("sub");
    },
  },
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第12张图片
从动图中可以看到devtools插件在记录着counter的状态改变,因为上面我们使用的是:

 this.$store.commit("add");//参数是提交给mutations的处理的函数名

用commit提交到mutations中的add()来更改counter的状态。

Mutations主要包括两部分:

  • 字符串的事件类型(即函数名)----->对应的则是add、sub
  • 一个回调函数,该回调函数的第一个参数就是state------>对应function函数

实例2:通过Mutations更改:按钮点击(绕过Mutations提交)

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50
  },
  mutations: {
     },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

由于它绕过mutations,所以这里mutations不定义任何东西。

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>counter:{
     {
     $store.state.counter}}</h3>
    <button @click="$store.state.counter+=5">+</button>
    <button @click="$store.state.counter-=5">-</button>
  </div>
</template>

<script>
export default {
     
  name: "App",
  methods: {
     },
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第13张图片
上面直接通过:

$store.state.counter+=5

来修改Vuex的state,所以是绕过了Mutations,所以从上面动图那里看到Vuex插件并没有记录状态的变化。因此,想要记录状态的变化,必须经过mutations。

5.3.2 携带参数

上面的例子是我直接在Mutations中:

mutations: {
     
    add: function(state) {
     
      state.counter += 5;
    },
    sub: function(state) {
     
      state.counter -= 5;
    }
  }

将每次累加或累减写成了5,那我想通过传过来的参数决定每次加减多少:

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50
  },
  mutations: {
     
    add: function(state, num) {
     
      state.counter += num;
    },
    sub: function(state, num) {
     
      state.counter -= num;
    }
  },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>counter:{
     {
     $store.state.counter}}</h3>
    <button @click="addition(10)">+</button>
    <button @click="subtraction(20)">-</button>
  </div>
</template>

<script>
export default {
     
  name: "App",
  methods: {
     
    addition(num) {
     
      this.$store.commit("add", num);
    },
    subtraction(num) {
     
      this.$store.commit("sub", num);
    },
  },
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第14张图片
即参数直接在提交的后面添加即可:

  this.$store.commit("add", num);
5.3.3 mutations的特殊提交风格
 this.$store.commit("add", num);

上面的这种提交风格,我们称为普通风格。

下面看看特殊的风格如何书写:

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50
  },
  mutations: {
     
    add: function(state, obj) {
     
      state.counter += obj.num;
      console.log(obj);
    },
    sub: function(state, num) {
     
      state.counter -= num;
    }
  },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:(注意区别)

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>counter:{
     {
     $store.state.counter}}</h3>
    <button @click="addition(10)">+</button>
    <button @click="subtraction(20)">-</button>
  </div>
</template>

<script>
export default {
     
  name: "App",
  methods: {
     
    addition(num) {
     
      this.$store.commit({
     
        type: "add",
        num,
      });
    },
    subtraction(num) {
     
      this.$store.commit("sub", num);
    },
  },
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第15张图片
上面只修改了addition()函数:

  • 注意它的参数是一个对象
  • type属性用于规定提交的mutations函数
  • 其它的则可以写传过去的参数

注意:

  • 在mutations的函数中,第二个参数不再是传过来的num
  • 而是定义的整个对象,上面我打印了第二个参数,可以看看。

5.4 Vuex-actions(异步函数在此操作)

通常情况下,Vuex要求在Mutations中的方法必须是同步方法。

  • 主要原因是当我们使用devtools时,devtools可以帮助我们捕抓mutation的快照。
  • 但是如果是异步操作,那么devtools将不能很好的追踪这个操作什么时候会被完成,即无法记录状态。

在这里强调,不要在Mutations中进行异步操作。

  • 但是某些情况下,我们确实希望在Vuex中进行一些异步操作,比如网络请求必然是异步的,这个时候该怎么处理。
  • Actions类似于Mutations,但是是用来代替Mutations进行异步操作的。

下面举例:在mutations中写个异步函数,看看能否被devtools捕抓

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50
  },
  mutations: {
     
    add: function(state, payload) {
     
      setTimeout(() => {
     
        state.counter += payload.num;
      }, 1000);
    },
    sub: function(state, payload) {
     
      setTimeout(() => {
     
        state.counter -= payload.num;
      }, 1000);
    }
  },
  actions: {
     },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>counter:{
     {
     $store.state.counter}}</h3>
    <button @click="addition(10)">+</button>
    <button @click="subtraction(20)">-</button>
  </div>
</template>

<script>
export default {
     
  name: "App",
  methods: {
     
    addition(num) {
     
      this.$store.commit({
     
        type: "add",
        num,
      });
    },
    subtraction(num) {
     
      this.$store.commit({
     
        type: "sub",
        num,
      });
    },
  },
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第16张图片
上面图片说明再Mutations使用异步函数是不合理的,虽然能正确显示数据,但是数据与抓捕的记录不一致,那使用Vuex就没有意义了。

举例:在Actions中使用异步函数

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     
    counter: 50
  },
  mutations: {
     
    add: function(state, payload) {
     
      state.counter += payload.num;
      console.log("payload对象:", payload);
    },
    sub: function(state, payload) {
     
      state.counter += payload.num;
    }
  },
  actions: {
     
    // context:上下文
    Add: function(context, num) {
     
      setTimeout(() => {
     
        console.log("context对象:", context);
        context.commit({
     
          type: "add",
          num
        });
      }, 1000);
    },
    Sub: function(context, num) {
     
      setTimeout(() => {
     
        context.commit({
     
          type: "sub",
          num
        });
      }, 1000);
    }
  },
  getters: {
     },
  modules: {
     }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>counter:{
     {
     $store.state.counter}}</h3>
    <button @click="addition(10)">+</button>
    <button @click="subtraction(20)">-</button>
  </div>
</template>

<script>
export default {
     
  name: "App",
  methods: {
     
    addition(num) {
     
      this.$store.dispatch("Add", num);
    },
    subtraction(num) {
     
      this.$store.dispatch("Sub", num);
    },
  },
};
</script>

<style></style>

记录结果:

Vue核心特性之Vuex用法 一篇足矣_第17张图片
异步流程,严格按照下图执行:

Vue核心特性之Vuex用法 一篇足矣_第18张图片

  • 在组件通过dispatch提交到Actions,
  • 在Actions进行异步处理,然后通过commit提交到Mutations,
  • 最后在Mutations进行state更新。

5.5 Vuex-modules

Module是模块的意思,为什么在Vuex中我们要使用模块呢》

  • Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理。
  • 当应用变得非常复杂时,store对象就变得相当臃肿。
  • 为了解决这个问题,Vuex允许我们将store分割成模块(Module),而每个模块拥有自己的state、mutations、actions、getters等。

在modules中写多个模块

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     },
  mutations: {
     },
  actions: {
     },
  getters: {
     },
  modules: {
     
    moduleA: {
     
      state: {
     },
      mutations: {
     },
      actions: {
     },
      getters: {
     }
    },
    moduleB: {
     
      state: {
     },
      mutations: {
     },
      actions: {
     },
      getters: {
     }
    }
  }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

上面在modules中定义了两个模块moduleA、moduleB。他们也有同样的特性,但一般不会再在模块(moduleA、moduleB)中定义modules属性。

如何使用modules中的数据:

store/index.js:

import Vue from "vue";
import Vuex from "vuex";

// 1.使用Vuex插件
Vue.use(Vuex);

// 2.创建Vuex对象
const store = new Vuex.Store({
     
  state: {
     },
  mutations: {
     },
  actions: {
     },
  getters: {
     },
  modules: {
     
    moduleA: {
     
      state: {
      name: "我是moduleA中state中的name" },
      mutations: {
     
        updateName: function(state) {
     
          state.name = "我是修改后的name";
        }
      },
      actions: {
     },
      getters: {
     
        fullName: function(state) {
     
          return state.name + "哈哈哈哈";
        }
      }
    }
  }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

App.vue:

<template>
  <div id="app">
    <hr />
    <h2>我是App.vue组件</h2>
    <h3>{
     {
     $store.state.moduleA.name}}</h3>
    <button @click="$store.commit('updateName')">修改</button>
    <h3>{
     {
     $store.getters.fullName}}</h3>
  </div>
</template>

<script>
export default {
     
  name: "App",
};
</script>

<style></style>

Vue核心特性之Vuex用法 一篇足矣_第19张图片

注意:

  • 获取modules中的state中的数据只需:$store.state.模块名.属性名
  • Actions、mutations、getters的操作同不在模块定义的完全一样

6. Vuex中的目录组织

当Vuex实例的数据过多时往往显得Vuex实例的内容很堵,开发中我们通常会将五个核心各个分成文件,最后通过es6的语法导出与引入各个文件:

目录:
Vue核心特性之Vuex用法 一篇足矣_第20张图片

在store/index.js:

import Vue from "vue";
import Vuex from "vuex";
import actions from "./actions";
import getters from "./getters";
import mutations from "./mutations";
import moduleA from "./modules/moduleA";
import moduleB from "./modules/moduleB";
// 1.使用Vuex插件
Vue.use(Vuex);

const state = {
     
  name: "在这里写state的属性"
};
// 2.创建Vuex对象,这里使用了es6的对象解构语法 即state:state缩写为state
const store = new Vuex.Store({
     
  state,
  actions,
  getters,
  mutations,
  modules: {
     
    moduleA,
    moduleB
  }
});

// 3.导出Vuex对象,因为Vue实例要使用
export default store;

这样就好多了。

你可能感兴趣的:(vue,前端,vue.js)