Vuex的初探与实战小结


Posted in Javascript onNovember 26, 2018

1.背景

最近在做一个单页面的管理后台项目,为了提高开发效率,使用了Vue框架来开发。为了使各个部分的功能,独立结构更加清晰,于是就拆分了很多组件,但是组件与组件之间数据共享成了一个问题,父子组件实现起来相对简单,prop,$emit,$on就能搞定。除此之外,有很多兄弟组件和跨多级组件,实现起来过程繁琐,在多人协同开发上,不利于统一管理,于是,开始了Vue的生态之一的Vux实践之旅。

2.概述

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。

Vuex 和单纯的全局对象有以下两点不同:

1.Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新;2.你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用

3.安装使用

3.1.使用Vue-cli开发安装vue包

cnpm install vuex --save

3.2.在src目录下创建store文件夹并创建index.js如下(src/store/index.js)

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
 state: {

 },
 getters: {

 },
 mutations: {

 },
 actions: {

 }
});

然后在src文件下的main.js中使用

import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false


new Vue({
 el: '#app',
 store,
 components: { App },
 template: '<App/>'
})

4.用法简介

 4.1.state

state是保存共享数据的,现在改store/index.js如下:

state: {
  count:0
 },

在components目录下创建Index.vue如:

<template>
 <div class="index">
  {{count}}
 </div>
</template>

<script>
 export default {
  name: "index",
  computed:{
   count(){
    return this.$store.state.count;
   }
  }
 }
</script>

结果如下:

Vuex的初探与实战小结

我们可以通过组件的计算属性来保存state里面的值,那么问题来了,如果store太多的话,我们组件里面的计算属性岂不是成了这个样子:

computed:{
 count(){
   return this.$store.state.count;
 },
  stateA(){
   return this.$store.state.stateA;
  },
  stateB(){
   return this.$store.state.stateB;
  }
}

这样获取共享状态的数据也没有什么问题不过看起来还是有大量的重复冗余代码,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键:

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。

import {mapState} from 'vuex'
 export default {
  name: "index",
  computed:{
   ...mapState(['count']),
  }
 }

小结:使用 Vuex 并不意味着你需要将所有的状态放入 Vuex。虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。

4.2.getter

有的时候我们需要对共享状态里面的某一个属性做一些处理后再使用,我们可以把数据获取后再在组件的计算属性中处理,举个例子如下:

// store/index.js
state: {
  count:0,
  numbers:[0,1,2,3,4,5,6,7,8]
 },
// Index组件
<template>
 <div class="index">
  {{count}}
  <br>
  {{numbers.join()}}
 </div>
</template>
<script>
 import {mapState} from 'vuex'
 export default {
  name: "index",
  computed:{
   ...mapState(['count']),
   numbers(){
    return this.$store.state.numbers.filter((item)=>{
     return item>3;
    })
   }
  }
 }
</script>

结果如下:

Vuex的初探与实战小结

那么问题来了,如果多个组件都要做同样的处理,我们就需要把一份代码复制到多个地方,显然是不大合理的,于是有了getter,可以理解为组件里面的计算属性。示例如下:

/ store/index.js
getters: {
  filterNumbers(state){
   return state.numbers.filter((item)=>{
    return item>3;
   })
  }
 },
// Index组件
<template>
 <div class="index">
  {{count}}
  <br>
  {{filterNumbers.join()}}
 </div>
</template>

<script>
 import {mapState} from 'vuex'
 export default {
  name: "index",
  computed:{
   ...mapState(['count']),
   filterNumbers(){
    return this.$store.getters.filterNumbers;
   }
  }
 }
</script>

结果完全一样,我们可以根据this.$store.getters.属性名来获取getters,也可以通过 mapGetters 辅助函数将 store 中的 getter 映射到局部计算属性: 

具体实现方式如下:

<template>
 <div class="index">
  {{count}}
  <br>
  {{filterNumbers.join()}}
  <br>
  {{antherNumbers.join()}}
 </div>
</template>

<script>
 import {mapState,mapGetters} from 'vuex'
 export default {
  name: "index",
  computed:{
   ...mapState(['count']),6
   ...mapGetters(['filterNumbers']),
   ...mapGetters({
    antherNumbers:'filterNumbers'
   })
  }
 }
</script>

如果用同一名字直接把数组作为参数,如果想改一个名字,可以传入一个对象作为参数,结果如下:

Vuex的初探与实战小结

4.3.mutation

在组件内,来自store的数据只能读取,不能手动改变,改变store中数据唯一的途径就是显示的提交mutations。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。改变代码如下:

// store/index.js
mutations: {
 add(state){
  state.count++;
 }
},

// Index组件
**
  <button @click="add">+</button>
**
  methods:{
   add(){
    this.$store.commit('add');
    console.log(this.count);
   }
**

Vuex的初探与实战小结

连续点击5次增加按钮,发现count的值也改变了。当然,我们也可以传参进去

// store/index.js
mutations: {
 add(state,n){
  state.count+=n;
 }
},

// Index组件
**
  <button @click="add">+</button>
**
  methods:{
   add(){
    this.$store.commit('add',10);
    console.log(this.count);
   }
**

触发方法语句为:this.$store.commit(方法名);也可以使用辅助函数mapMutations代替:

methods:{
  ...mapMutations(['add']),
}

4.4.action

前面我们讲过,mutation有必须同步执行这个限制,我们在业务需求中有时候需要在获取ajax请求数据之后再操作或定时器操作数据,这些都属于异步请求,要用actions来实现。具体实现如下:

// store/index.js
mutations: {
  changeCount(state){
   state.count=3000;
  },
 },
 actions: {
  changeCount3000s(context){
   setTimeout(()=>{
    context.commit('changeCount')
   },3000)

// Index组件
<button @click="changeCount3000s">点击按钮3s后count的值改变</button>
methods:{
 ...mapMutations(['add']),
  changeCount3000s(){
    this.$store.dispatch('changeCount3000s');
  }
 }

我们在点击按钮3s后count的值改变为3000,我们可以通过this.$store.dispatch(方法名)来触发事件,也可以通过辅助函数mapActions来触发。

import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
  methods:{
   ...mapMutations(['add']),
   ...mapActions(['changeCount3000s'])
  }

学会以上几个属性的使用基本就可以满足平时业务中的需求了,但使用Vuex会有一定的门槛和复杂性,它的主要使用场景是大型单页面应用,如果你的项目不是很复杂,用一个bus也可以实现数据的共享,但是它在数据管理,维护,还只是一个简单的组件,而Vuex可以更优雅高效地完成状态管理,所以,是否使用Vuex取决于你的团队和技术储备。

参考资料:

《Vue.js实践》  Vuex

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

Javascript 相关文章推荐
ExtJS GTGrid 简单用户管理
Jul 01 Javascript
jQuery学习笔记之jQuery.fn.init()的参数分析
Jun 09 Javascript
JS实现简易图片轮播效果的方法
Mar 25 Javascript
jQuery选择器源码解读(一):Sizzle方法
Mar 31 Javascript
jquery实现移动端点击图片查看大图特效
Sep 11 Javascript
微信小程序 登陆流程详细介绍
Jan 17 Javascript
Angular 4依赖注入学习教程之Injectable装饰器(六)
Jun 04 Javascript
初识 Vue.js 中的 *.Vue文件
Nov 22 Javascript
vue-cli webpack配置文件分析
May 20 Javascript
jquery中attr、prop、data区别与用法分析
Sep 25 jQuery
Element Alert警告的具体使用方法
Jul 27 Javascript
一篇超完整的Vue新手入门指导教程
Nov 18 Vue.js
微信小程序页面间值传递的两种方法
Nov 26 #Javascript
Vue中的methods、watch、computed的区别
Nov 26 #Javascript
vue-router懒加载速度缓慢问题及解决方法
Nov 25 #Javascript
移动端滑动切换组件封装 vue-swiper-router实例详解
Nov 25 #Javascript
vue中选项卡点击切换且能滑动切换功能的实现代码
Nov 25 #Javascript
vue中tab选项卡的实现思路
Nov 25 #Javascript
Cookbook组件形式:优化 Vue 组件的运行时性能
Nov 25 #Javascript
You might like
搜索引擎技术核心揭密
2006/10/09 PHP
php file_get_contents取文件中数组元素的方法
2017/04/01 PHP
Laravel中错误与异常处理的用法示例
2018/09/16 PHP
PHP利用pdo_odbc实现连接数据库示例【基于ThinkPHP5.1搭建的项目】
2019/05/13 PHP
js相册效果代码(点击创建即可)
2013/04/16 Javascript
javascript:void(0)的作用示例介绍
2013/10/28 Javascript
instanceof和typeof运算符的区别详解
2014/01/06 Javascript
jquery解析XML字符串和XML文件的方法说明
2014/02/21 Javascript
离开当前页面前使用js判断条件提示是否要离开页面
2014/05/02 Javascript
jQuery滚动新闻实现代码
2016/06/26 Javascript
jQuery基于xml格式数据实现模糊查询及分页功能的方法
2016/12/25 Javascript
JavaScript事件处理程序详解
2017/09/19 Javascript
vue2.0 computed 计算list循环后累加值的实例
2018/03/07 Javascript
vue 中filter的多种用法
2018/04/26 Javascript
vue.js实现标签页切换效果
2018/06/07 Javascript
JavaScript日期工具类DateUtils定义与用法示例
2018/09/03 Javascript
Vue.js组件间通信方式总结【推荐】
2018/11/23 Javascript
PHP实现基于Redis的MessageQueue队列封装操作示例
2019/02/02 Javascript
浅谈javascript错误处理
2019/08/11 Javascript
JS原型和原型链原理与用法实例详解
2020/02/05 Javascript
[19:14]DOTA2 HEROS教学视频教你分分钟做大人-维萨吉
2014/06/24 DOTA
python生成圆形图片的方法
2020/03/25 Python
mac 安装python网络请求包requests方法
2018/06/13 Python
Magee 1866官网:Donegal粗花呢外套和大衣专家
2019/11/01 全球购物
MediaMarkt比利时:欧洲最大电器连锁店
2020/12/21 全球购物
在weblogic中发布ejb需涉及到哪些配置文件
2012/01/17 面试题
同步和异步有何异同,在什么情况下分别使用他们?
2012/12/28 面试题
Boolean b = new Boolean(“abcde”); 会编译错误码
2013/11/27 面试题
大学生冰淇淋店商业计划书
2014/01/14 职场文书
大学生评语大全
2014/04/18 职场文书
优质服务演讲稿
2014/05/14 职场文书
公司离职证明范本(汇总)
2014/09/10 职场文书
2015年学生资助工作总结
2015/05/25 职场文书
微信小程序和php的登录实现
2021/04/01 PHP
nginx服务器的下载安装与使用详解
2021/08/02 Servers
Vue自定义铃声提示音组件的实现
2022/01/22 Vue.js