Vue的Flux框架之Vuex状态管理器


Posted in Javascript onJuly 30, 2017

学习vue之前,最重要是弄懂两个概念,一是“what”,要理解vuex是什么;二是“why”,要清楚为什么要用vuex。

Vuex是什么?

Vuex 类似 React 里面的 Redux 的状态管理器,用来管理Vue的所有组件状态。

为什么使用Vuex?

当你打算开发大型单页应用(SPA),会出现多个视图组件依赖同一个状态,来自不同视图的行为需要变更同一个状态。
遇到以上情况时候,你就应该考虑使用Vuex了,它能把组件的共享状态抽取出来,当做一个全局单例模式进行管理。这样不管你在何处改变状态,都会通知使用该状态的组件做出相应修改。

下面讲解如何使用Vuex

一个简单的Vuex示例

本文就讲解安装Vuex,直接通过代码讲解Vuex使用。

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

上面就是一个简单的Vuex示例,每一个Vuex应用就是一个store,在store中包含组件中的共享状态state和改变状态的方法(暂且称作方法)mutations。

需要注意的是只能通过mutations改变store的state的状态,不能通过store.state.count = 5;直接更改(其实可以更改,不建议这么做,不通过mutations改变state,状态不会被同步)。

使用store.commit方法触发mutations改变state:

store.commit('increment');

console.log(store.state.count) // 1

一个简简单单的Vuex应用就实现了。

在Vue组件使用Vuex

如果希望Vuex状态更新的时候,组件数据得到相应的更新,那么可以用计算属性computed获取state的更新状态。

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count;
    }
  }
}

每一个store.state都是全局状态,在使用Vuex时候需要在根组件或(入口文件)注入。

// 根组件
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);
const app = new Vue({
  el: '#app',
  store,
  components: {
    Counter
  },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

通过这种注入机制,就能在子组件Counter通过this.$store访问:

// Counter 组件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}

mapState函数

computed: {
  count () {
    return this.$store.state.count
  }
}

上面通过count计算属性获取同名state.count属性,如何每一次获取都要写一个这样的方法,是不显得重复又麻烦?可以使用mapState函数简化这个过程。

import { mapState } from 'vuex';

export default {
  computed: mapState ({
    count: state => state.count,
    countAlias: 'count',  // 别名 `count` 等价于 state => state.count
  })
}

还有更简单的使用方法:

computed: mapState([
 'count' 
 // 映射 this.count 为 store.state.count
])

Getters对象

如果我们需要对state对象进行做处理计算,如下:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

如果多个组件都要进行这样的处理,那么就要在多个组件中复制该函数。这样是很没有效率的事情,当这个处理过程更改了,还有在多个组件中进行同样的更改,这就更加不易于维护。

Vuex中getters对象,可以方便我们在store中做集中的处理。Getters接受state作为第一个参数:

const store = new Vuex.Store({
 state: {
  todos: [
   { id: 1, text: '...', done: true },
   { id: 2, text: '...', done: false }
  ]
 },
 getters: {
  doneTodos: state => {
   return state.todos.filter(todo => todo.done)
  }
 }
})

在Vue中通过store.getters对象调用:

computed: {
 doneTodos () {
  return this.$store.getters.doneTodos
 }
}

Getter也可以接受其他getters作为第二个参数:

getters: {
 doneTodos: state => {
   return state.todos.filter(todo => todo.done)
 },
 doneTodosCount: (state, getters) => {
  return getters.doneTodos.length
 }
}

mapGetters辅助函数

与mapState类似,都能达到简化代码的效果。mapGetters辅助函数仅仅是将store中的getters映射到局部计算属性:

import { mapGetters } from 'vuex'

export default {
 // ...
 computed: {
  // 使用对象展开运算符将 getters 混入 computed 对象中
  ...mapGetters([
   'doneTodosCount',
   'anotherGetter',
   // ...
  ])
 }
}

上面也可以写作:

computed: mapGetters([
   'doneTodosCount',
   'anotherGetter',
   // ...
  ])

所以在Vue的computed计算属性中会存在两种辅助函数:

import { mapState, mapGetters } from 'vuex';

export default {
  // ...
  computed: {
    ...mapGetters([ ... ]),
    ...mapState([ ... ])
  }
}

Mutations

之前也说过了,更改Vuex的store中的状态的唯一方法就是mutations。

每一个mutation都有一个事件类型type和一个回调函数handler。

调用mutation,需要通过store.commit方法调用mutation type:

store.commit('increment')

Payload 提交载荷

也可以向store.commit传入第二参数,也就是mutation的payload:

mutaion: {
  increment (state, n) {
    state.count += n;
  }
}

store.commit('increment', 10);

单单传入一个n,可能并不能满足我们的业务需要,这时候我们可以选择传入一个payload对象:

mutation: {
  increment (state, payload) {
    state.totalPrice += payload.price + payload.count;
  }
}

store.commit({
  type: 'increment',
  price: 10,
  count: 8
})

mapMutations函数

不例外,mutations也有映射函数mapMutations,帮助我们简化代码,使用mapMutations辅助函数将组件中的methods映射为store.commit调用。

import { mapMutations } from 'vuex'

export default {
 // ...
 methods: {
  ...mapMutations([
   'increment' // 映射 this.increment() 为 this.$store.commit('increment')
  ]),
  ...mapMutations({
   add: 'increment' // 映射 this.add() 为 this.$store.commit('increment')
  })
 }
}

Actions

注 Mutations必须是同步函数。

如果我们需要异步操作和提交多个Mutations,Mutations就不能满足我们需求了,这时候我们就需要Actions了。

Actions

Action 类似于 mutation,不同在于:

  1. Action 提交的是 mutation,而不是直接变更状态。
  2. Action 可以包含任意异步操作。

让我们来注册一个简单的 action:

var store = new Vuex.Store({
 state: {
  count: 0
 },
 mutations: {
  increment: function(state) {
   state.count++;
  }
 },
 actions: {
  increment: function(store) {
   store.commit('increment');
  }
 }
});

分发 Action

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。

分发 Action

Action 通过 store.dispatch 方法触发:

乍一眼看上去感觉多此一举,我们直接分发 mutation 岂不更方便?实际上并非如此,还记得 mutation必须同步执行这个限制么?Action就不受约束! 我们可以在 action 内部执行异步操作:

actions: {
 incrementAsync ({ commit }) {
  setTimeout(() => {
   commit('increment')
  }, 1000)
 }
}

Actions 支持同样的载荷方式和对象方式进行分发:

// 以载荷形式分发
store.dispatch('incrementAsync', {
 amount: 10
})

// 以对象形式分发
store.dispatch({
 type: 'incrementAsync',
 amount: 10
})

mapActions

同样地,action也有相对应的mapActions 辅助函数

mapActions

mapActions 辅助函数跟mapMutations一样都是组件的 methods 调用:

import { mapActions } from 'vuex'

export default {
 // ...
 methods: {
  ...mapActions([
   'increment' // 映射 this.increment() 为 this.$store.dispatch('increment')
  ]),
  ...mapActions({
   add: 'increment' // 映射 this.add() 为 this.$store.dispatch('increment')
  })
 }
}

mutation-types

关于mutation-types方面的讲解官方文档很少说明,但在实际的中大项目中,对==mutation-types==的配置是必不可少的,Vuex的文档只讲解了state,getters,mutation,actions四个核心概念,下面我简单补充下mutation-types的使用。

顾名思义,==mutation-types==其实就是mutation实例中各个方法的设定,一般要mutation方法前先在mutation-types用大写写法设定,再在mutation里引入使用,下面看看项目实际使用:

项目组织结构

Vue的Flux框架之Vuex状态管理器

在mutation-types定义好mutation的方法结构:

//SET_SINGER,SET_SONG 为mutation中要使用的方法名

export const SET_SINGER = 'SET_SINGER'

export const SET_SONG = 'SET_SONG'

在mutation中导入使用:

import * as types from ',/mutation-types.js'

const mutations = {
  [types.SET_SINGER](state, singer) {
    .... 
  },
  [types.SET_SONG](state, song) {
    .... 
  }
}

结语

看完上面对vuex的讲解相信你已经入门了,现在可以看看具体的项目加深理解,可以参考我的github一个购物车例子: https://github.com/osjj/vue-shopCart

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript定义类或函数的几种方式小结
Jan 09 Javascript
jquery和ajax的关系详细介绍
Nov 29 Javascript
js在数组中删除重复的元素自保留一个(两种实现思路)
Aug 22 Javascript
js实现二代身份证号码验证详解
Nov 20 Javascript
JS定时检测任务任务完成后执行下一步的解决办法
Dec 22 Javascript
如何理解jQuery中的ajaxSubmit方法
Mar 13 Javascript
angular2 ng build部署后base文件路径问题详细解答
Jul 15 Javascript
vue2.x+webpack快速搭建前端项目框架详解
Nov 30 Javascript
Angular实现模版驱动表单的自定义校验功能(密码确认为例)
May 17 Javascript
vue实现组件之间传值功能示例
Jul 13 Javascript
小程序根据手机机型设置自定义底部导航距离
Jun 04 Javascript
jQuery实现轮播图效果
Nov 26 jQuery
webpack实现热加载自动刷新的方法
Jul 30 #Javascript
利用JavaScript如何查询某个值是否数组内
Jul 30 #Javascript
Angular.js中上传指令ng-upload的基本使用教程
Jul 30 #Javascript
关于前后端json数据的发送与接收详解
Jul 30 #Javascript
jquery easyui如何实现格式化列
Jul 30 #jQuery
微信小程序对接七牛云存储的方法
Jul 30 #Javascript
利用node.js+mongodb如何搭建一个简单登录注册的功能详解
Jul 30 #Javascript
You might like
在“咖啡之国”感受咖啡文化
2021/03/03 咖啡文化
Yii结合CKEditor实现图片上传功能
2014/06/13 PHP
Win7 64位系统下PHP连接Oracle数据库
2014/08/20 PHP
php数组实现根据某个键值将相同键值合并生成新二维数组的方法
2017/04/26 PHP
PHP实现的日历功能示例
2018/09/01 PHP
ExtJS 2.0实用简明教程之应用ExtJS
2009/04/29 Javascript
实现png图片和png背景透明(支持多浏览器)的方法
2009/09/08 Javascript
JQuery 确定css方框模型(盒模型Box Model)
2010/01/22 Javascript
JavaScript语言核心数据类型和变量使用介绍
2013/08/23 Javascript
javascript操作ul中li的方法
2015/05/14 Javascript
基于jQuery实现响应式圆形图片轮播特效
2015/11/25 Javascript
JS代码随机生成姓名、手机号、身份证号、银行卡号
2016/04/27 Javascript
基于Bootstrap仿淘宝分页控件实现代码
2016/11/07 Javascript
BootStrap整体框架之基础布局组件
2016/12/15 Javascript
二维码图片生成器QRCode.js简单介绍
2017/08/18 Javascript
js封装成插件的步骤方法
2017/09/11 Javascript
vue-cli中安装方法(图文详细步骤)
2018/12/12 Javascript
原生js实现分页效果
2020/09/23 Javascript
用Python代码来绘制彭罗斯点阵的教程
2015/04/03 Python
Python中列表元素转为数字的方法分析
2016/06/14 Python
解决Mac下首次安装pycharm无project interpreter的问题
2018/10/29 Python
Python字典的基本用法实例分析【创建、增加、获取、修改、删除】
2019/03/05 Python
Python多项式回归的实现方法
2019/03/11 Python
python执行scp命令拷贝文件及文件夹到远程主机的目录方法
2019/07/08 Python
Django项目中使用JWT的实现代码
2019/11/04 Python
计算Python Numpy向量之间的欧氏距离实例
2020/05/22 Python
通用C#笔试题附答案
2016/11/26 面试题
sleep()方法和wait()方法的区别是什么
2012/11/17 面试题
校园公益广告语
2014/03/13 职场文书
2014党员自我评议表范文
2014/09/20 职场文书
出纳岗位职责
2015/01/31 职场文书
人事聘任通知
2015/04/21 职场文书
歌舞青春观后感
2015/06/10 职场文书
个人合作协议范本
2015/08/06 职场文书
MySql开发之自动同步表结构
2021/05/28 MySQL
中国十大神话动漫电影排行榜 哪吒登顶 白蛇缘起排第七
2022/03/21 国漫