关于Vuex相关知识的一些总结

Vuex介绍

Vuex是做什么的,有什么作用?应用场景又有哪些,其实在官网已有相应的介绍,这里引用官网的一些观点:

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

作为一个刚毕业的前端萌新,接触到的项目比较少,根据自己实际经历目前我用的的vuex的地方主要存在在管理系统中登录校验通过后,来存储用户的信息,另外由于vuex存储的一个特点在刷新界面时Vuex中的数据会被清空.那么在用来存储登录过的用户信息是不太适合的或者说Vuex的能力还不足以达到这样一个需求。所以目前我所接触过的管理系统中用来存储用户信息,通常会和js-cookie这样一个操作cookie的插件来一起使用,通过分发action等一系列操作,最终将数据存储到cookie中去,保证在刷新界面时数据不会丢失。具体怎么实现,继续往后看吧。

Vuex的基础使用

说完了Vuex的基本概念以及自己在实际运用中的应用场景,我们来看下Vuex的基本使用。
可参照博客VueJS中学习使用Vuex详解

Vuex的进阶使用

当一个项目有多个信息需要进行维护,比如用户的个人信息需要进行管理,根据权限不同展示不同的管理系统左侧下拉菜单。这时候如果再使用上面的用法,会造成这个状态管理内容过多,且可读性不强。这时候需要用到另外一种模式。即使用module将store分隔成不同的模块.使用方法如下。
第一步:在项目中建立一个名为store的文件夹,该文件夹下下面有一个modules文件夹和一个index.js文件,其中modules文件夹中存在两个文件。分别为collection.jsfootStatus文件。整个项目结构如图所示。
在这里插入图片描述
其中两个js文件的代码如下

//collection.js
const collection = {
	//namespace: true 的作用等会来说明
//	namespance: true, 
	state: {//相当于vue实例中的data属性
		collects: []
	},
	getters: {	//相当于vue实例中的计算属性
		renderCollects(state){ //承载变化的collects
   			return state.collects;
  		}
  	},
  	mutations:{	//相当于vue实例中methods方法
  		pushCollects(state,items){ //如何变化collects,插入items
	      state.collects.push(items)
	    }
	},
	actions: {	//actions中的方法是用来提交mutations中的方法,因为mutations中的方法要想触发,必须分发actions中的方法才可以。
		increment({commit},item){ //触发mutations里面的pushCollects ,传入数据			形参item 对应到items
      	commit('pushCollects',item);
    }
}
//最后将这个js文件给暴露出去
export default collection	
// footStatus.js文件
const footStatus = {
//	namespace:true, 同上这一行的作用等会来说明
	state: {
	   	showFooter: true,
	    changableNum: 0
	},
  	getters: {  //实时监听state值的变化(最新状态)
	    isShow(state) {  //承载变化的showFooter的值
	    	return state.showFooter
	    },
	    getChangedNum(state){  //承载变化的changebleNum的值
	    	return state.changableNum
	    }
  	},
  	mutations: {
	    show(state) {   //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象);
	    	state.showFooter = true;
	    },
	    hide(state) {  //同上
	    	state.showFooter = false;
	    },
	    newNum(state,sum){ //同上,这里面的参数除了state之外还传了需要增加的值sum
	    	state.changableNum+=sum;
	    }
  	},
	actions: {
		hideFooter(context) {  //自定义触发mutations里函数的方法,context与store 实例具有相同方法和属性
	    	context.commit('hide');
	    },
	    showFooter(context) {  //同上注释
	      	context.commit('show');
	    },
	    getNewNum(context,num){   //同上注释,num为要变化的形参
	      	context.commit('newNum',num)
	    }
	}	
}
//同前一个js文件一样,将这个js文件给暴露出去
export default footStatus

有了两个js文件之后,需要在store文件夹中的index.js文件中进行引入

//index.js文件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import collection from './modules/collection';
import footStatus from './modules/footStatus';
export default new Vuex.Store({
	modules:{
		collection,
		footStatus
	}
//有些时候还会有全局的getters、mutations、actions
//	getters:{
//		...
//	},
//	mutations:{
//		...
//	},
//	actions:{
//		...
//	}
})	

有了上面几个文件之后,在实际中该如何使用呢,我们不妨来写个例子做个演示使用。如图所示,拟实现的效果,当我们点击button按钮上面的值也跟着变化。如图所示。
在这里插入图片描述
当然实际中,这种不可能利用vuex来实现,这里只是借此来演示一下vuex的各种用法。上代码:

<template>
  <div class="vuexs-container" style="width: 600px;border:1px solid blue;margin: auto;">
    <div style="margin-bottom: 30px;">计算属性:{{collects}}</div>
    <button @click="initData">改变store</button>
    <p style="margin-top:60px;">{{num}}</p>
  </div>
</template>
<script>
export default {
  name: 'Vuexs',
  data(){
    return {
      num: 1,
      collects: []
    }
  },
  computed: {
    
  },
  methods: {
    initData(){
   	  //通过this.$store.state后加上指定的模块名称,再引用对应的属性值就可以获取store中存储的值,并且state中的值变化,页面上的值也随着变化。
      this.collects = this.$store.state.collection.collects;
      //点击一次,向collection.js的collects中加入一个5
      this.collects.push(5);
      console.log(this.$store.state.collection.collects)
    }
  }
}
</script>

说到这里可能有人会想,通过这种方式,能够响应的获取到state中的值,为啥还需要用getters.(之前不是说getters相当于计算属性,就是为了在数据发生变化时实时的更新吗?)
那代码上的这种方式行不行呢?肯定是可以,毕竟已经达到预期的结果了吗,但确不好?原因个人觉得有以下两点:①如果在该界面有多个属性需要获取,我们都用this.$store.state这种方式将它定义在data中,是不是会显得很累赘。②上面的代码,我们可以看到实际上是直接将内存地址赋给了this.collects,作为一个合格的程序员,这种事还是少干的好。你说是吧?
那么问题来了,如果想在组件中使用store中的state属性,具体该怎么做呢,那就不得不提三个流弊的函数 mapSate、mapGetters、mapActions。具体怎么使用,

mapState的使用

我们来看下。还是之前那张图要求实现的效果。看看利用mapState函数的使用方式。

<template>
  <div class="vuexs-container" style="width: 600px;border:1px solid blue;margin: auto;">
    <div style="margin-bottom: 30px;">计算属性:{{collects}}</div>
    <button @click="initData">改变store</button>
    <p style="margin-top:60px;">{{num}}</p>
  </div>
</template>
<script>
//将需要利用的函数引入
import {mapState,mapMutations,mapActions} from 'vuex';
export default {
  name: 'Vuexs',
  data(){
    return {
      num: 1
    }
  },
  //第一种computed写法
  computed: {
  	//mapState返回的是一个对象,利用ES6语法的解构赋值,将其中的属性展开,如果你不想用...mapState这种方式,也没有问题,看第二种computed写法
 	...mapState({
 		//collects是自定义计算属性名可以不是collects,后面的collects是collection.js中的collects值
		collects: (state) => state.collection.collects
	})	 
  },
  //第二种computed写法,mapState不是返回一个对象吗,那么我们就将mapState结果赋给computed不就好了。但更推荐用第一种种方式
//  computed: mapState({
//  	collects: (state) => state.collection.collects
//  }),	 
  methods: {
    initData(){
      //点击一次,向collection.js的collects中加入一个5
      //下面两种方式任选一个即可
      //第一种写法,直接利用this.$store,state来赋值,但当要维护的数据多了这种方式就不太好,太累赘,所以还是建议用第二种方式。
      this.$store.state.collection.collects.push(5);
      //第二种写法,分发actions中的方法来实现改变state的值
      this.$store.dispatch('increament',5)	//分发action指定方法然后触发mutations中的指定方法。 
    }
  }
}
</script>

上面就是我对mapState用法的一点简单认识吧。这里补充个之前未解决的问题。在最开始写collection.jsfootStatus.js时,我们将第一行namespaced:true给注释掉了,那这一行又是什么作用呢?namespace:true是用于在全局引用此文里的方法时标识这一个的文件名,还是不明白?那就实际操作一把好了,一切都将明明白白。
将两个js文件的namespace:true都给加上,然后运行上面这个index.vue文件对应的文件,发现点击button的时候报错了,提示vuex.esm.js?2f62:419 [vuex] unknown action type: increment
在这里插入图片描述
为什么会出现这个情况呢,就是因为namespaced:true这行导致,当我们加了这行后,它唯一标识了这个文件,无法在全局访问到。那怎么办?最简单的方式就是namespaced:true这行给去了,那如果我偏偏不去掉这行(就是这么傲娇),怎么办呢?那就改一下分发的方式好了,将最后一行改为

this.$store.dispatch('collection/increment',5)

就是这么简单,也就是你如果加了```namespaced:true``这行,你在分发该模块中的方法时,必须在方法前面加上指定的js文件名称。

mapGetters的使用

说完了mapState的使用,我们来看看mapGetters的用法,同mapSate类似,它对应的是模块中的getters属性,返回的也是一个对象。
拟实现,在向store加入一个数据时,计算出collects第一个值和最后一个值的和。
在这里插入图片描述
请看第一种实现方式

<template>
  <div class="vuexs-container" style="width: 600px;border:1px solid blue;margin: auto;">
    <div style="margin-bottom: 30px;">计算属性:{{collects}}</div>
    <button @click="initData">改变store</button>
    <p>
      <span>{{collects[0]}}</span>+
      <span>{{collects[collects.length-1]}}</span>=
      <span>{{collectsNum}}</span>
    </p>
    <p style="margin-top:60px;">{{num}}</p>
  </div>
</template>
<script>
import {mapState,mapMutations,mapActions} from 'vuex';
export default {
  name: 'Vuexs',
  data(){
    return {
      num: 5
    }
  },
  computed: {
    ...mapState({
      collects: (state)=>state.collection.collects
    }),
    collectsNum(){	//这个计算属性用来返回相加的结果
      var item =this.$store.state.collection.collects;
      return (item[0] + item[item.length -1])
    }
  },
  methods: {
    initData(){
      this.num++;
      this.$store.dispatch('collection/increment',this.num);
    }
  }
}
</script>

通过上面的代码可以实现,但这并不是我们想要的,看上去也不是太好,既然vuex中存在getters,相当于computed,那对vuex中的数据修改我们为何不把他放在vuex模块的getters中去,而放到组件中呢。这也不利于其他组件的复用,如果其他组件还想用这个计算属性,那我们在其他组件中是不是又要重新写一遍,不是增加了重复的代码,看着也很不舒服吗。那怎么办呢?
我们不妨在collections.js的基础上,在getters中添加一个属性,用于返回值相加的结果。

//collection.js
cosnt collection ={
	...
	getters: {
		renderCollects(state){ //承载变化的collects
   			return state.collects;
  		},
  		//计算第一个和最后一个相加结果
  		collectsSum(state){
  			return state.collects[0] + state.collects[state.collects.length-1]
  		}
	},
	...
}

那这时候在组件中该怎么使用呢,只需要将之前的computed中的collectsNum计算属性换成下面这样就行了

.......
computed: {
    ...mapState({
      collects: (state)=>state.collection.collects
    }),
    
    //第一种方式
//     collectsNum(){	//这个计算属性用来返回相加的结果
//      var item =this.$store.state.collection.collects;
 //     return (item[0] + item[item.length -1])
//    }

	//第二种方式
    ...mapGetters({
      //第一个为自定义的计算属性,第二个为collection.js中的getters中存在的属性
      collectsNum: 'collectsSum'
    })
  },
......

是不是看着很舒服,而且可复用性更强。

mapActions的使用

有了前面mapState和mapGetters的举例之后,mapActions是不是也变得很简单了呢,只不过mapActions是放在methods中,除此之外其他用法类似。

<template>
  <div class="vuexs-container" style="width: 600px;border:1px solid blue;margin: auto;">
    <div style="margin-bottom: 30px;">计算属性:{{collects}}</div>
    <!-- <button @click="initData">改变store</button> -->
    <button @click="increment(num)">改变store</button>
    <p>
      <span>{{collects[0]}}</span>+
      <span>{{collects[collects.length-1]}}</span>=
      <span>{{collectsNum}}</span>
    </p>
    <p style="margin-top:60px;">{{num}}</p>
  </div>
</template>
<script>
import {mapState,mapMutations,mapActions, mapGetters} from 'vuex';
export default {
  name: 'Vuexs',
  data(){
    return {
      num: 5
    }
  },
  computed: {
    ...mapState({
      collects: (state)=>state.collection.collects
    }),
    ...mapGetters({
      //第一个为自定义的计算属性,第二个为collection.js中的getters中存在的属性
      collectsNum: 'collectsSum'
    })
  },
  methods: {
    // 之前的方式
      // initData(){
      //   this.num++;
      //   this.$store.dispatch('increment',this.num);
      // }
    // 现在的方式,如果没有加namespaced:true这行,就这么使用
    ...mapActions([
      'increment'
    ])
    //如果加了namespaced:true这行,就像下面这样使用,需要指定actions方法所在的模块
    // ...mapActions('collection',[
    //   'increment'
    // ])
  }
}
</script>
需要注意一下加了namespaced: true 和没有加namespaced:true时的mapActions
用法上的区别

以上是我对Vuex相关知识点的一个总结和回顾。部分内容参考了博客VueJS中学习使用Vuex详解

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值