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 相关文章推荐
判断是否输入完毕再激活提交按钮
Jun 26 Javascript
jQuery库与其他JS库冲突的解决办法
Feb 07 Javascript
js 3秒后跳转页面的实现代码
Mar 10 Javascript
使用js获取图片原始尺寸
Dec 03 Javascript
JavaScript基本数据类型及值类型和引用类型
Aug 25 Javascript
JS组件Bootstrap实现弹出框和提示框效果代码
Dec 08 Javascript
浅谈vue中使用图片懒加载vue-lazyload插件详细指南
Oct 23 Javascript
Vue基础学习之项目整合及优化
Jun 02 Javascript
jQuery实现验证用户登录
Dec 10 jQuery
基于vue 动态菜单 刷新空白问题的解决
Aug 06 Javascript
Node在Controller层进行数据校验的过程详解
Aug 28 Javascript
js实现移动端轮播图滑动切换
Dec 21 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
完整删除ecshop中获取店铺信息的API
2014/12/24 PHP
百度工程师讲PHP函数的实现原理及性能分析(二)
2015/05/13 PHP
Yii框架Session与Cookie使用方法示例
2019/10/14 PHP
jquery 跨域访问问题解决方法(笔记)
2011/06/08 Javascript
『jQuery』.html(),.text()和.val()的概述及使用
2013/04/22 Javascript
Js 代码中,ajax请求地址后加随机数防止浏览器缓存的原因
2013/05/07 Javascript
完美兼容各大浏览器获取HTTP_REFERER方法总结
2014/06/24 Javascript
JSON字符串转换JSONObject和JSONArray的方法
2016/06/03 Javascript
浅谈JavaScript的内置对象和浏览器对象
2016/06/03 Javascript
简单谈谈ES6的六个小特性
2016/11/18 Javascript
Jquery给当前页或者跳转后页面的导航栏添加选中后样式的实例
2016/12/08 Javascript
webpack+vue-cli项目中引入外部非模块格式js的方法
2018/09/28 Javascript
js实现延迟加载的几种方法详解
2019/01/19 Javascript
使用React手写一个对话框或模态框的方法示例
2019/04/25 Javascript
layui(1.0.9)文件上传upload,前后端的实例代码
2019/09/26 Javascript
解决vue中的无限循环问题
2020/07/27 Javascript
Python求两个list的差集、交集与并集的方法
2014/11/01 Python
在Python中使用Neo4j的方法
2019/03/14 Python
python检测服务器端口代码实例
2019/08/31 Python
Python常用模块os.path之文件及路径操作方法
2019/12/03 Python
世界上最大的汽车共享网站:Zipcar
2017/01/14 全球购物
Pretty Little Thing美国:时尚女性服饰
2018/08/27 全球购物
澳大利亚购买健身器材网站:Gym Direct
2019/12/19 全球购物
设计部经理的岗位职责
2013/11/16 职场文书
十月份红领巾广播稿
2014/01/22 职场文书
《台湾的蝴蝶谷》教学反思
2014/02/20 职场文书
大学学风建设方案
2014/05/04 职场文书
经理任命书模板
2014/06/06 职场文书
庆六一宣传标语
2014/10/08 职场文书
2015年世界环境日活动总结
2015/02/11 职场文书
采购员岗位职责范本
2015/04/07 职场文书
2016教师校本培训心得体会
2016/01/08 职场文书
nginx如何将http访问的网站改成https访问
2021/03/31 Servers
JS 4个超级实用的小技巧 提升开发效率
2021/10/05 Javascript
JavaScript文档对象模型DOM
2021/11/20 Javascript
Python使用OpenCV实现虚拟缩放效果
2022/02/28 Python