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 Keycode对照表
Oct 24 Javascript
JS判断字符串长度的5个方法(区分中文和英文)
Mar 18 Javascript
HTML页面弹出居中可拖拽的自定义窗口层
May 07 Javascript
jQuery ajax方法传递中文时出现中文乱码的解决方法
Jul 25 Javascript
移动端使用localStorage缓存Js和css文的方法(web开发)
Sep 20 Javascript
vue2中filter()的实现代码
Jul 09 Javascript
原生js获取left值和top值的三种方法
Aug 02 Javascript
vue 实现 ios 原生picker 效果及实现思路解析
Dec 06 Javascript
Javascript中的作用域及块级作用域
Dec 08 Javascript
基于vue 实现token验证的实例代码
Dec 14 Javascript
vue 移动端适配方案详解
Nov 15 Javascript
vue ajax 拦截原理与实现方法示例
Nov 29 Javascript
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
php中switch语句用法详解
2015/08/17 PHP
给PHP开发者的编程指南 第一部分降低复杂程度
2016/01/18 PHP
jQuery DOM操作小结与实例
2010/01/07 Javascript
jQuery 获取对象 定位子对象
2010/05/31 Javascript
html a标签-超链接中confirm方法使用介绍
2013/01/04 Javascript
一个js控制的导航菜单实例代码
2013/12/03 Javascript
js获取上传文件大小示例代码
2014/04/10 Javascript
jQuery中的ajax async同步和异步详解
2015/09/29 Javascript
JavaScript使用DeviceOne开发实战(四)仿优酷视频应用
2015/12/02 Javascript
bootstrap css样式之表单
2017/01/19 Javascript
如何用js判断dom是否有存在某class的值
2017/02/13 Javascript
详解Vue文档中几个易忽视部分的剖析
2018/03/24 Javascript
vue-cli 打包使用history模式的后端配置实例
2018/09/20 Javascript
小程序Request的另类用法详解
2019/08/09 Javascript
JS中的算法与数据结构之列表(List)实例详解
2019/08/16 Javascript
判断JavaScript中的两个变量是否相等的操作符
2019/12/21 Javascript
使用Vant完成DatetimePicker 日期的选择器操作
2020/11/12 Javascript
Python微信库:itchat的用法详解
2017/08/14 Python
python中安装django模块的方法
2020/03/12 Python
解决pyqt5异常退出无提示信息的问题
2020/04/08 Python
将pymysql获取到的数据类型是tuple转化为pandas方式
2020/05/15 Python
python中round函数保留两位小数的方法
2020/12/04 Python
Whittard官方海外旗舰店:英国百年茶叶品牌
2018/02/22 全球购物
高中生自我鉴定范文
2013/10/30 职场文书
岗位职责风险点
2014/03/12 职场文书
南京青奥会口号
2014/06/12 职场文书
商铺消防安全责任书
2014/07/29 职场文书
教师先进个人材料
2014/12/17 职场文书
巾帼文明岗事迹材料
2014/12/24 职场文书
房地产公司工程部经理岗位职责
2015/04/09 职场文书
加班费申请报告
2015/05/15 职场文书
民事上诉状范文
2015/05/22 职场文书
紫日观后感
2015/06/05 职场文书
Python基础之常用库常用方法整理
2021/04/30 Python
MySql 8.0及对应驱动包匹配的注意点说明
2021/06/23 MySQL
MySQL数据库之存储过程 procedure
2022/06/16 MySQL