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 相关文章推荐
拖动一个HTML元素
Dec 22 Javascript
ExtJS 2.2.1的grid控件在ie6中的显示问题
May 04 Javascript
jquery nth-child()选择器的简单应用
Jul 10 Javascript
JQuery入门——移除绑定事件unbind方法概述及应用
Feb 05 Javascript
模拟电子签章盖章效果的jQuery插件源码
Jun 24 Javascript
jquery实现手风琴效果实例代码
Nov 15 Javascript
javascript 数组排序函数sort和reverse使用介绍
Nov 21 Javascript
js 获取、清空input type=&quot;file&quot;的值(示例代码)
Dec 24 Javascript
一个html5播放视频的video控件只支持android的默认格式mp4和3gp
May 08 Javascript
jQuery实现全选、反选和不选功能
Aug 16 jQuery
vue学习笔记五:在vue项目里面使用引入公共方法详解
Apr 04 Javascript
VUE动态生成word的实现
Jul 26 Javascript
微信小程序页面间值传递的两种方法
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
php摘要生成函数(无乱码)
2012/02/04 PHP
WordPress迁移时一些常见问题的解决方法整理
2015/11/24 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
php连接oracle数据库的方法(测试成功)
2016/05/26 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
2019/04/02 PHP
如何确保JavaScript的执行顺序 之实战篇
2011/03/03 Javascript
jquery随机展示头像代码
2011/12/21 Javascript
javascript全局变量封装模块实现代码
2012/11/28 Javascript
input输入框的自动匹配(原生代码)
2013/03/19 Javascript
jquery中map函数与each函数的区别实例介绍
2014/06/23 Javascript
jquery实现鼠标拖拽滑动效果来选择数字的方法
2015/05/04 Javascript
jQuery实现响应鼠标背景变化的动态菜单效果代码
2015/08/27 Javascript
js实现不重复导入的方法
2016/03/02 Javascript
JQuery之proxy实现绑定代理方法
2016/08/01 Javascript
JS简单实现点击复制链接的方法
2016/08/03 Javascript
基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)
2016/11/17 Javascript
js中string和number类型互转换技巧(分享)
2016/11/28 Javascript
javascript删除html标签函数cIsHTML
2017/01/09 Javascript
vue-socket.io跨域问题有效解决方法
2020/02/11 Javascript
ant design vue datepicker日期选择器中文化操作
2020/10/28 Javascript
[01:01:31]2018DOTA2亚洲邀请赛3月29日小组赛B组 Mineski VS paiN
2018/03/30 DOTA
用pickle存储Python的原生对象方法
2017/04/28 Python
python 函数传参之传值还是传引用的分析
2017/09/07 Python
Python编程使用tkinter模块实现计算器软件完整代码示例
2017/11/29 Python
对DJango视图(views)和模版(templates)的使用详解
2019/07/17 Python
浅谈Python中的模块
2020/06/10 Python
python爬虫使用requests发送post请求示例详解
2020/08/05 Python
Python如何批量生成和调用变量
2020/11/21 Python
2020年10款优秀的Python第三方库,看看有你中意的吗?
2021/01/12 Python
SQL Server 2000数据库的文件有哪些,分别进行描述
2013/03/30 面试题
求职推荐信
2013/10/28 职场文书
公司委托书格式范本
2014/09/16 职场文书
单位接收函格式
2015/01/30 职场文书
python中Tkinter 窗口之输入框和文本框的实现
2021/04/12 Python
解决Swagger2返回map复杂结构不能解析的问题
2021/07/02 Java/Android
以下牛机,你有几个
2022/04/05 无线电