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 相关文章推荐
多广告投放代码 推荐
Nov 13 Javascript
Javascript实现DIV滚动自动滚动到底部的代码
Mar 01 Javascript
关于图片的预加载过程中隐藏未知的
Dec 19 Javascript
js和as的稳定传值问题解决
Jul 14 Javascript
javascript中文本框中输入法切换的问题
Dec 10 Javascript
JS实现跟随鼠标闪烁转动色块的方法
Feb 26 Javascript
jQuery实现在下拉列表选择时获取json数据的方法
Apr 16 Javascript
js实现的全国省市二级联动下拉选择菜单完整实例
Aug 17 Javascript
JS使用eval()动态创建变量的方法
Jun 03 Javascript
jQuery EasyUI 获取tabs的实例解析
Dec 06 Javascript
微信小程序 Buffer缓冲区的详解
Jul 06 Javascript
简单实现vue验证码60秒倒计时功能
Oct 11 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中array_merge和array相加的区别分析
2013/06/17 PHP
PHP中filter函数校验数据的方法详解
2015/07/31 PHP
php微信公众号js-sdk开发应用
2016/11/28 PHP
js技巧--转义符&quot;\&quot;的妙用
2007/01/09 Javascript
JavaScript 利用Cookie记录用户登录信息
2009/12/08 Javascript
jquery下为Event handler传递动态参数的代码
2011/01/06 Javascript
JavaScript 函数惰性载入的实现及其优点介绍
2013/08/12 Javascript
原生的html元素选择器类似jquery选择器
2014/10/15 Javascript
BootStrap Fileinput初始化时的一些参数
2016/12/30 Javascript
Bootstrap3 图片(响应式图片&amp;图片形状)
2017/01/04 Javascript
移动端刮刮乐的实现方式(js+HTML5)
2017/03/23 Javascript
vue组件如何被其他项目引用
2017/04/13 Javascript
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
详解React Native网络请求fetch简单封装
2017/08/10 Javascript
JS实现移动端触屏拖拽功能
2018/07/31 Javascript
使用JS实现导航切换时高亮显示的示例讲解
2018/08/22 Javascript
对VUE中的对象添加属性
2018/09/18 Javascript
基于Vue 服务端Cookies删除的问题
2018/09/21 Javascript
JavaScript实现学生在线做题计时器功能
2018/12/05 Javascript
JavaScript生成随机验证码代码实例
2019/09/28 Javascript
JS数据类型STRING使用实例解析
2019/12/18 Javascript
Element-ui el-tree新增和删除节点后如何刷新tree的实例
2020/08/31 Javascript
[01:04:22]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 IG vs EG
2018/04/01 DOTA
python应用程序在windows下不出现cmd窗口的办法
2014/05/29 Python
在Python的Django框架中实现Hacker News的一些功能
2015/04/17 Python
Java及python正则表达式详解
2017/12/27 Python
选择python进行数据分析的理由和优势
2019/06/25 Python
Matplotlib配色之Colormap详解
2021/01/05 Python
德国购买健身器材:AsVIVA
2017/08/09 全球购物
马来西亚网上花店:FlowerAdvisor马来西亚
2020/01/03 全球购物
建筑行业的大学生自我评价
2013/12/08 职场文书
揠苗助长教学反思
2014/02/04 职场文书
微信搭讪开场白
2015/05/28 职场文书
nginx反向代理时如何保持长连接
2021/03/31 Servers
Python中OpenCV实现查找轮廓的实例
2021/06/08 Python
Python自动化测试PO模型封装过程详解
2021/06/22 Python