什么是Vuex

专门为vue应用程序开发的状态管理模式,采用集中式存储管理应用的所有组件的状态(数据),以相应的规则保证状态以一种可预测的方式发生改变

Vuex的作用(什么样的情况下使用Vuex)

多个视图依赖于同一个状态(数据),来自不同视图的行为需要变更同一状态

Vuex的流程图和操作结构图

假设这个组件需要从后台拿到数据,那么就牵扯到异步操作,所以将异步操作定义在Actions中,组件中触发这个Actions,Actions中执行异步请求,拿到后台接口,然后拿到数据,需要将数据提交一个mutations改变状态,然后重新渲染组件中的状态

vuex 核心概念和 API

state:vuex 管理的状态对象,它应该是唯一的

  1. const state = {
  2. xxx: initValue
  3. }

mutations:包含多个直接更新 state 的方法(回调函数)的对象,谁来触发: action 中的 commit('mutation 名称'),只能包含同步的代码, 不能写异步代码

  1. const mutations = {
  2. yyy (state, {data1}) {
  3. // 更新 state 的某个属性
  4. }
  5. }

actions:包含多个事件回调函数的对象,通过执行:commit()来触发 mutation 的调用, 间接更新 state,谁来触发: 组件中: $store.dispatch('action 名称', data1),可以包含异步代码(定时器, ajax)

  1. const actions = {
  2. zzz ({commit, state}, data1) {
  3. commit('yyy', {data1})
  4. }
  5. }

getters:包含多个计算属性(get)的对象,谁来读取: 组件中: $store.getters.xxx

  1. const getters = {
  2. mmm (state) {
  3. return ...
  4. }
  5. }

modules:包含多个 module,一个 module 是一个 store 的配置对象,与一个组件(包含有共享数据)对应

Vuex的基本使用(通过一个简易计算器实例分析Vuex流程)

首先使用脚手架初始化一项vue的项目,并且App.vue组件中引入一个组件(简易计算器的这么一个组件)

  1. <template>
  2. <div>
  3. <h2>简易加法计算器</h2>
  4. <div>
  5. <input type="button" value="-" />
  6. <span>{{count}}</span>
  7. <input type="button" value="+" />
  8. </div>
  9. </div>
  10. </template>
  11.  
  12. <script>
  13. export default {
  14. }
  15. </script>
  16. <style>
  17.  
  18. </style>
  1. <template>
  2. <div id="app">
  3. <increment></increment>
  4. </div>
  5. </template>
  6.  
  7. <script>
  8. import Increment from './components/Increment'
  9.  
  10. export default {
  11. name: 'app',
  12. components: {
  13. Increment
  14. }
  15. }
  16. </script>
  17.  
  18. <style>
  19. #app {
  20. font-family: 'Avenir', Helvetica, Arial, sans-serif;
  21. -webkit-font-smoothing: antialiased;
  22. -moz-osx-font-smoothing: grayscale;
  23. text-align: center;
  24. color: #2c3e50;
  25. margin-top: 60px;
  26. }
  27. </style>

然后启动项目,可以看到下面的界面

接下来先安装vuex模块

然后src目录中创建一个vuex的目录,在里面创建一个store.js的一个文件,用于操作vuex,并且将vue和vuex导入进来,将vuex作为插件使用

定义一个容器,并且将这个容器导出去,这个store容器,包含应用中的大部分状态,store的特点:

一个页面只能有一个store

状态存储是响应式的(就是说当state中的某个状态值发生改变的时候,使用了这个状态值的组件中的数据也会跟着改变,所以只要改变state中的状态就可以了)

不能直接改变store中的状态,唯一途径就是显示地提交mutations

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. Vue.use(Vuex)
  5.  
  6. // 定义一个容器
  7. const store = new Vuex.Store({
  8.  
  9. })
  10. export default store

然后再mian.js中注入(注入根实例),之后就可以使用vuex来管理状态了,注入的时候需要注意,store小写

  1. // The Vue build version to load with the `import` command
  2. // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
  3. import Vue from 'vue'
  4. import App from './App'
  5. import store from './vuex/store'
  6.  
  7. Vue.config.productionTip = false
  8.  
  9. /* eslint-disable no-new */
  10. new Vue({
  11. el: '#app',
  12. store,
  13. template: '<App/>',
  14. components: { App }
  15. })

在store容器中定义一个对象,叫做state,里面存放的都是应用中共享的状态(数据),也就是说包含所有应用级别状态的对象,比如下面定义一个count的状态

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. Vue.use(Vuex)
  5.  
  6. // 定义一个容器
  7. const store = new Vuex.Store({
  8. state: {
  9. count: 100
  10. }
  11. })
  12. export default store

然后在需要这个状态值的组件中拿到这个状态值,就是在组件中使用this(当前组件的实例对象).$store(因为这个store已经在main.js中注入进来了,所以每个组件都可以访问到这个store).state

然后在这个state中拿到想要的那个状态值

  1. <template>
  2. <div>
  3. <h2>简易加法计算器</h2>
  4. <div>
  5. <input type="button" value="-" />
  6. <span>{{ num }}</span>
  7. <input type="button" value="+"/>
  8. </div>
  9. </div>
  10. </template>
  11.  
  12. <script>
  13. export default {
  14. computed: {
  15. num () {
  16. return this.$store.state.count
  17. }
  18. }
  19. }
  20. </script>

接着在组件中通过事件来触发改变state里面的某个状态值,改变state中的状态值需要通过Mutations(唯一修改状态的事件回调函数)

状态存储是响应式的(就是说当state中的某个状态值发生改变的时候,使用了这个状态值的组件中的数据也会跟着改变,所以只要改变state中的状态就可以了)

不能直接改变store中的状态,唯一途径就是显示地提交mutations

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. Vue.use(Vuex)
  5.  
  6. // 定义一个容器
  7. const store = new Vuex.Store({
  8. state: {
  9. count: 100
  10. },
  11. mutations: {
  12. // 这里里面定义改变状态值的一些函数(需要接收一个state作为参数,也就是state容器)
  13. addincrement (state) {
  14. state.count += 1
  15. },
  16. deincrement (state) {
  17. state.count -= 1
  18. }
  19. }
  20. })
  21. export default store

然后再组件中通过事件来提交一个mutations并且触发里面相应函数

  1. <template>
  2. <div>
  3. <h2>简易加法计算器</h2>
  4. <div>
  5. <input type="button" value="-" @click="deHandler"/>
  6. <span>{{ num }}</span>
  7. <input type="button" value="+" @click="addHandler"/>
  8. </div>
  9. </div>
  10. </template>
  11.  
  12. <script>
  13. export default {
  14. computed: {
  15. num () {
  16. return this.$store.state.count
  17. }
  18. },
  19. methods: {
  20. addHandler () {
  21. this.$store.commit('addincrement')
  22. },
  23. deHandler () {
  24. this.$store.commit('deincrement')
  25. }
  26. }
  27. }
  28. </script>

测试,点击加号或者就可以改变count这个状态值,并且查看vue调试工具可以看到数据的变化

在点击事件提交一个mutations的时候,可以传入第二个参数,比如下面我想要点击一次加5或者减5

  1. addHandler () {
  2. this.$store.commit('addincrement', 5)
  3. },
  4. deHandler () {
  5. this.$store.commit('deincrement', 5)
  6. }

在容器中的mutations可以接收第二个参数,这个参数叫做payload

  1. mutations: {
  2. // 这里里面定义改变状态值的一些函数(需要接收一个state作为参数,也就是state容器)
  3. addincrement (state, n) {
  4. state.count += n
  5. },
  6. deincrement (state, n) {
  7. state.count -= n
  8. }
  9. }

运行测试可以看到,点击一次以5来计算

当需要传递很多个参数的时候,第二个参数写成对象的形式

  1. methods: {
  2. addHandler () {
  3. this.$store.commit('addincrement', {
  4. n: 5
  5. })
  6. },
  7. deHandler () {
  8. this.$store.commit('deincrement', {
  9. n: 5
  10. })
  11. }
  12. }
  1. mutations: {
  2. // 这里里面定义改变状态值的一些函数(需要接收一个state作为参数,也就是state容器)
  3. addincrement (state, payload) {
  4. state.count += payload.n
  5. },
  6. deincrement (state, payload) {
  7. state.count -= payload.n
  8. }
  9. }

运行测试:

还可以使用下面这种写法:mutations中接收参数也是一样的写法接收一个payload,然后获取payload下的某个参数值

  1. methods: {
  2. addHandler () {
  3. this.$store.commit({
  4. type: 'addincrement',
  5. n: 5
  6. })
  7. },
  8. deHandler () {
  9. this.$store.commit({
  10. type: 'deincrement',
  11. n: 5
  12. })
  13. }
  14. }

Action异步操作

当点击某个按钮需要从后台请求数据的时候,这个时候有异步的操作,这里就使用上面的例子来模拟一下异步的操作

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. Vue.use(Vuex)
  5.  
  6. // 定义一个容器
  7. const store = new Vuex.Store({
  8. state: {
  9. count: 100
  10. },
  11. mutations: {
  12. // 这里里面定义改变状态值的一些函数(需要接收一个state作为参数,也就是state容器)
  13. addincrement (state, payload) {
  14. state.count += payload.n
  15. },
  16. deincrement (state, payload) {
  17. state.count -= payload.n
  18. }
  19. },
  20. actions: {
  21. addAction (context) {
  22. setTimeout(() => {
  23. // 改变状态,提交mutations
  24. context.commit('addincrement', {
  25. n: 5
  26. })
  27. }, 1000)
  28. }
  29. }
  30. })
  31. export default store

在组件中触发的时候,先触发actions,然后在提交mutations

  1. <template>
  2. <div>
  3. <h2>简易加法计算器</h2>
  4. <div>
  5. <input type="button" value="-" @click="deHandler"/>
  6. <span>{{ num }}</span>
  7. <input type="button" value="+" @click="addHandler"/>
  8. </div>
  9. </div>
  10. </template>
  11.  
  12. <script>
  13. export default {
  14. computed: {
  15. num () {
  16. return this.$store.state.count
  17. }
  18. },
  19. methods: {
  20. addHandler () {
  21. // 触发Actions
  22. this.$store.dispatch('addAction')
  23. },
  24. deHandler () {
  25. this.$store.commit({
  26. type: 'deincrement',
  27. n: 5
  28. })
  29. }
  30. }
  31. }
  32. </script>

getters计算属性

包含多个计算属性(get)的对象,谁来读取: 组件中: $store.getters.xxx

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. Vue.use(Vuex)
  5.  
  6. // 定义一个容器
  7. const store = new Vuex.Store({
  8. state: {
  9. count: 100
  10. },
  11. mutations: {
  12. // 这里里面定义改变状态值的一些函数(需要接收一个state作为参数,也就是state容器)
  13. addincrement (state, payload) {
  14. state.count += payload.n
  15. },
  16. deincrement (state, payload) {
  17. state.count -= payload.n
  18. }
  19. },
  20. actions: {
  21. addAction (context) {
  22. setTimeout(() => {
  23. // 改变状态,提交mutations
  24. context.commit('addincrement', {
  25. n: 5
  26. })
  27. }, 1000)
  28. }
  29. },
  30. getters: {
  31. oddOrEven (state) {
  32. return state.count % 2 === 0 ? '偶数' : '奇数'
  33. }
  34. }
  35. })
  36. export default store
  1. <template>
  2. <div>
  3. <h2>简易加法计算器</h2>
  4. <div>
  5. <input type="button" value="-" @click="deHandler"/>
  6. <span>{{ num }}, is {{ oddOrEven2 }}</span>
  7. <input type="button" value="+" @click="addHandler"/>
  8. </div>
  9. </div>
  10. </template>
  11.  
  12. <script>
  13. export default {
  14. computed: {
  15. num () {
  16. return this.$store.state.count
  17. },
  18. oddOrEven2 () {
  19. return this.$store.getters.oddOrEven
  20. }
  21. },
  22. methods: {
  23. addHandler () {
  24. // 触发Actions
  25. this.$store.dispatch('addAction')
  26. },
  27. deHandler () {
  28. this.$store.commit({
  29. type: 'deincrement',
  30. n: 5
  31. })
  32. }
  33. }
  34. }
  35. </script>

vuex的API使用

mapState的使用:直接获取state中的某个数据

mapGetters的使用:获取getters中的对应的get名称的返回值

mapActions的使用:触发store下的actios下对应的action,事件名称跟action的名称需要一样(开发中一般不这么写,不可以传递参数)

mapMutations的使用:跟mapActions的使用一样

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. Vue.use(Vuex)
  5.  
  6. // 定义一个容器
  7. const store = new Vuex.Store({
  8. state: {
  9. count: 100
  10. },
  11. mutations: {
  12. // 这里里面定义改变状态值的一些函数(需要接收一个state作为参数,也就是state容器)
  13. addincrement (state, payload) {
  14. state.count += payload.n
  15. },
  16. deHandler (state) {
  17. state.count -= 1
  18. }
  19. },
  20. actions: {
  21. addHandler (context) {
  22. setTimeout(() => {
  23. // 改变状态,提交mutations
  24. context.commit('addincrement', {
  25. n: 5
  26. })
  27. }, 1000)
  28. }
  29. },
  30. getters: {
  31. oddOrEven (state) {
  32. return state.count % 2 === 0 ? '偶数' : '奇数'
  33. }
  34. }
  35. })
  36. export default store
  1. <template>
  2. <div>
  3. <h2>简易加法计算器</h2>
  4. <div>
  5. <input type="button" value="-" @click="deHandler"/>
  6. <span>{{ count }}, is {{ oddOrEven2 }}</span>
  7. <input type="button" value="+" @click="addHandler"/>
  8. </div>
  9. </div>
  10. </template>
  11.  
  12. <script>
  13. import {mapState, mapGetters, mapActions, mapMutations} from 'vuex'
  14.  
  15. export default {
  16. computed: {
  17. ...mapState(['count']), // 直接获取state下的count这个数据,相当于这个组件中有了count这个变量,可以任意地方this.count获取这个数据,但是不能直接修改
  18. ...mapGetters({ // 直接获取getters返回的值,可以获取多个对应的getters
  19. oddOrEven2: 'oddOrEven'
  20. })
  21. },
  22. methods: {
  23. ...mapActions(['addHandler']), // 事件名称跟actions名称一样
  24. ...mapMutations(['deHandler']) // 事件名跟对应的Mutations名称一致
  25. }
  26. }
  27. </script>

实际开发项目中应该如何使用vuex

实际开发项目中我们不会像上面那样去使用vuex,首先我们会将每个功能模块对应一个stote文件,然后通过module来合并到store.js文件中,下面来做一个实例

目录结构

这里是两个模块feeds和movies

  1. store
  2. index.js

  3. ├─feeds.js

  4. └─movies.js

第一步:在store文件夹下的index.js入口文件写入

  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3.  
  4. import Vue from 'vue';
  5. import Vuex from 'vuex';
  6. import feeds from './feeds';
  7. import Movies from './movies';
  8.  
  9. Vue.use(Vuex)
  10.  
  11. // 全局状态对象
  12. const state = {}
  13.  
  14. // 全局mutations
  15. let mutations = {}
  16.  
  17. let getters = {}
  18.  
  19. let actions = {}
  20.  
  21. export default new Vuex.Store({
  22. state: state,
  23. mutations: mutations,
  24. getters: getters,
  25. actions: actions,
  26. modules: {
  27. feeds,
  28. movies: Movies
  29. }
  30. })

第二步:在每个模块内的index文件这组装所有的零件(state,actions,mutations,getters),并且输出

注意上面多出的一行,我们在组件里怎么区分不同模块呢?namespaced写成true,意思就是可以用这个module名作为区分了(也就是module所在的文件夹名)

  1. export default {
  2. namespaced: true,
  3. state: {},
  4. actions: {},
  5. mutations: {},
  6. getters: {}
  7. }

第三步:在组件里使用获取state中的数据,在组件的计算属性中写

如果是全局下的state

  1. ...mapState(['userInfo', 'isInNative'])

如果是模块下的state,这里表示获取movies模块下的projectApplyId这个数据

  1. ...mapState('movies', ['projectApplyId'])

第四步:触发actions操作,在组件的methods中写

  1. store.dispatch('pi/taskSaveAndSubmit', {projectLockKey: that.projectLockKey})
  1. ...mapActions('movies',[
  2. 'foo',
  3. 'bar'
  4. ])

Vuex状态管理详解的更多相关文章

  1. 前端Vue框架-vuex状态管理详解

    新人报道!多多关照-多提宝贵意见 谢谢- vuex理解 采用集中式存储管理模式.用来管理组件的状态,并以自定义规则去观测实时监听值得变化. 状态模式管理理解 属性 理解 state 驱动应用的数据源 ...

  2. ASP.NET状态管理详解,让你明明白白

    开发WinFrom的程序员可能不会在意维护应用程序的状态,因为WinFrom本身就在客户端运行,可以直接在内存中维护其应用程序状态.但ASP.NET应用程序在服务器端运行,客户端使用无状态的http协 ...

  3. Oracle权限管理详解

    Oracle权限管理详解 转载--CzmMiao的博客生活 Oracle 权限 权限允许用户访问属于其它用户的对象或执行程序,ORACLE系统提供三种权限:Object 对象级.System 系统级. ...

  4. (转)Spring事务管理详解

    背景:之前一直在学习数据库中的相关事务,而忽略了spring中的事务配置,在阿里面试时候基本是惨败,这里做一个总结. 可能是最漂亮的Spring事务管理详解 https://github.com/Sn ...

  5. 可能是最漂亮的Spring事务管理详解

    Java面试通关手册(Java学习指南):https://github.com/Snailclimb/Java_Guide 微信阅读地址链接:可能是最漂亮的Spring事务管理详解 事务概念回顾 什么 ...

  6. 可能是最漂亮的Spring事务管理详解 专题

    微信阅读地址链接:可能是最漂亮的Spring事务管理详解 事务概念回顾 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行. 事物的特性(ACID): 原子性: 事务是最小的执行单位,不允 ...

  7. 最漂亮的Spring事务管理详解

    SnailClimb 2018年05月21日阅读 7245 可能是最漂亮的Spring事务管理详解 Java面试通关手册(Java学习指南):github.com/Snailclimb/- 微信阅读地 ...

  8. HTTP协议 (六) 状态码详解

    HTTP协议 (六) 状态码详解 HTTP状态码,我都是现查现用. 我以前记得几个常用的状态码,比如200,302,304,404, 503. 一般来说我也只需要了解这些常用的状态码就可以了.  如果 ...

  9. js基础--浏览器标签页隐藏或显示状态 visibility详解

    欢迎访问我的个人博客:http://www.xiaolongwu.cn 前言 在工作中我们可能会遇到这样的需求,当浏览器切换到别的标签页或着最小化时,我们需要暂停页面上正在播放的视频或者音乐,这个需求 ...

随机推荐

  1. [转]Magento 2.2 Developer Documentation

    本文转自:https://devdocs.magento.com/

  2. C# Thread.Abort方法真的让线程停止了吗?

    大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Threa ...

  3. 在.net中序列化读写xml方法的总结--转载过来学习学习

    原文章地址:http://www.cnblogs.com/fish-li/archive/2013/05/05/3061816.html 首先做个大概的总结,XML包括的元素有XmlElement,X ...

  4. oracle 备份数据库,导出数据库

    导出数据库 exp hljslfh2/hljslfh@dbsvr file=d:\hljslfh2Of0426.dmp 导入数据库 imp hljslfh2/hljslfh@localhost/dbs ...

  5. CentOS7 配置静态IP

    在mini安装完CentOS7后,如果想让电脑能够上网,则必须要进行网络配置. 本虚拟机使用NAT模式上网,网络配置步骤如下: ifconfig命令查到机器网卡: vi /etc/sysconfig/ ...

  6. vue 相对路径的图片 不显示问题

    例如 data () { return { img: '../../images/jifen/index/img_list_default_pic.jpg' //路径也没问题啊,怎么不显示呢,难道他瞎 ...

  7. JS实现自定义排序

    定义:用本地特定的顺序来比较两个字符串. 语法:stringObject.localeCompare(target) 参数:target——要以本地特定的顺序与 stringObject 进行比较的字 ...

  8. 高性能JavaScript(DOM编程)

    首先什么是DOM?为什么慢? DOM:文档对象模型,是一个独立于语言的,用于操作XML和HTML文档的程序接口(API) 用脚本进行DOM操作的代价很昂贵.那么,怎样才能提高程序的效率? 1.DOM访 ...

  9. SD从零开始33-37

    [原创]SD从零开始33 Billing简介 Billing在SD流程链中的集成: Billing document表征SD流程链中的最后功能: Billing document在R/3系统的不同区域 ...

  10. springboot 1.3.5升级1.5.9后 默认使用tomcat 8.5版本 get请求报400 异常信息为 The valid characters are defined in RFC 7230 and RFC 3986

    1.springboot 1.3.5升级1.5.9后 默认使用tomcat 8.5版本而之前用的是tomcat7    get请求报400 异常信息为 The valid characters are ...