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 相关文章推荐
点击隐藏页面左栏或右栏实现js代码
Apr 01 Javascript
JavaScript判断密码强度(自写代码)
Sep 06 Javascript
jquery删除提示框弹出是否删除对话框
Jan 07 Javascript
Webpack 实现 Node.js 代码热替换
Oct 22 Javascript
封装好的javascript前端分页插件pagination
Jan 04 Javascript
详解Vue中过度动画效果应用
May 25 Javascript
Vue.js对象转换实例
Jun 07 Javascript
JS实现给数组对象排序的方法分析
Jun 24 Javascript
KnockoutJS数组比较算法实例详解
Nov 25 Javascript
uniapp实现横向滚动选择日期
Oct 21 Javascript
vue 函数调用加括号与不加括号的区别
Oct 29 Javascript
CentOS 8.2服务器上安装最新版Node.js的方法
Dec 16 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 随机数的产生、页面跳转、件读写、文件重命名、switch语句
2009/08/07 PHP
优化php效率,提高php性能的一些方法
2011/03/24 PHP
PHP中使用cURL实现Get和Post请求的方法
2013/03/13 PHP
php处理带有中文URL的方法
2016/07/11 PHP
Yii框架分页技术实例分析
2019/08/30 PHP
js 弹出菜单/窗口效果
2011/10/30 Javascript
JavaScript全排列的六种算法 具体实现
2013/06/29 Javascript
详解maxlength属性在textarea里奇怪的表现
2015/12/27 Javascript
AngularJS基础 ng-readonly 指令简单示例
2016/08/02 Javascript
关于Jquery中的bind(),on()绑定事件方式总结
2016/10/26 Javascript
基于node.js依赖express解析post请求四种数据格式
2017/02/13 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
Vue.js实战之通过监听滚动事件实现动态锚点
2017/04/04 Javascript
Javascript创建类和对象详解
2017/05/31 Javascript
解决vue router使用 history 模式刷新后404问题
2017/07/19 Javascript
微信小程序之自定义组件的实现代码(附源码)
2018/08/02 Javascript
Koa代理Http请求的示例代码
2018/10/10 Javascript
Vue表单控件数据绑定方法详解
2020/02/05 Javascript
jQuery实现移动端扭蛋机抽奖
2020/11/08 jQuery
Python抓取Discuz!用户名脚本代码
2013/12/30 Python
pygame学习笔记(2):画点的三种方法和动画实例
2015/04/15 Python
Python简单实现区域生长方式
2020/01/16 Python
关于Python Tkinter Button控件command传参问题的解决方式
2020/03/04 Python
Python基于unittest实现测试用例执行
2020/11/25 Python
宝塔面板出现“open_basedir restriction in effect. ”的解决方法
2021/03/14 PHP
各大浏览器 CSS3 和 HTML5 兼容速查表 图文
2010/04/01 HTML / CSS
奥兰多迪士尼门票折扣:Undercover Tourist
2018/07/09 全球购物
艺术系应届生的自我评价
2013/10/19 职场文书
感恩节活动方案
2014/01/27 职场文书
热爱祖国的演讲稿
2014/05/04 职场文书
会计专业自荐信
2014/06/03 职场文书
劳动争议和解协议书范本
2014/11/20 职场文书
小石潭记导游词
2015/02/03 职场文书
感恩的心主题班会
2015/08/12 职场文书
党性教育心得体会(共6篇)
2016/01/21 职场文书
VUE解决跨域问题Access to XMLHttpRequest at
2022/05/06 Vue.js