本文已参与[新人创作礼]活动,一起开启掘金创作之路。
Vuex简介
Vuex是在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个应用组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
Vuex的使用场景:
1.多个组件依赖于同一个状态。
2.来自不同组件的行为需要变更同一状态。
Vuex的原理图(官网):
Actions、Mutations、State都是对象。
其中,由store来管理Actions、Mutations、State。
官网对于Vuex的介绍地址:vuex.vuejs.org/zh/
Vuex环境
安装插件
vuex现在默认安装的都是vuex4版本,vuex4版本只能在vue3中使用。
因为使用的vue2,所以需要安装vuex3版本。
安装vuex3版本:
npm install vuex@3
创建store
创建store管理actions、mutations、state。
在src目录下创建store文件夹,再在store文件里面创建一个index.js文件,该文件用于创建Vuex中最为核心的store。
store配置文件:index.js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 使用Vuex
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作,数据的异步操作。
const actions = {}
// 准备mutations-用于操作数据(state),处理数据的唯一途径,state的改变或赋值只能在这里。
const mutations = {}
// 准备state-用于存储数据,共同维护的一个状态,state里面可以是很多个全局状态。
const state = {}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
在main.js中引入store并配置:
import Vue from 'vue'
import App from './App.vue'
import VueLazyLoad from 'vue-lazyload'
// 引入路由文件
import router from '@/router/index'
// 引入store文件
import store from '@/store/index'
Vue.config.productionTip = false
Vue.use(VueLazyLoad, {
preLoad: 1.3,
error: require('./assets/img/logo.png'),
loading: require('./assets/img/logo.png'),
attempt: 1
})
new Vue({
// 配置router
router,
// 配置Store
store,
render: h => h(App),
}).$mount('#app')
这时,全部组件就有store($store)了。
班级组件,打印组件实例对象:
<template>
<div>
这是学校里面班级的信息
<input type="text" />
</div>
</template>
<script>
export default {
name: 'ClassInfo',
mounted(){
// 打印组件实例对象
console.log(this);
}
}
</script>
<style lang="less">
</style>
可以看见$store:
业务逻辑和发送请求等操作在actions中实现。
简单的Vuex实现
思路就是:
1.调用dispatch,触发actions对象里面的方法a。
2.actions对象里面的方法a调用commit,触发mutations对象里面的方法A。
3.mutations对象里面的方法A操作state对象,修改state对象里面的值。
4.使用$store.state获取state对象,即可使用state对象里面的值。
如果没有业务逻辑、发送请求等操作,可直接走commit,不走dispatch。
这里实现一个功能,在班级组件里面修改班级名字,学生组件里面也会显示修改后的班级名字。
当然直接用组件通信也可实现,但是涉及组件过多时,采用vuex就很方便,这里先全部走dispatch->commit。
1.输入班级名字,点击修改按钮,班级名字就修改(这是直接修改,没有业务逻辑和发送请求操作)。
2.输入班级名字,需要判断当前是否是A班级,如果是A班级,就不能修改(这里就有一个简单的判断班级名字的业务场景)。
班级组件:
<template>
<div>
<span>这是学校里面班级的信息,这里是{{$store.state.className || '--'}}班</span>
<div>
请输入修改后班级名字:<input type="text" v-model="className" placeholder="请输入班级名字"/>
</div>
<button class="button-name" @click="changeName">直接修改</button>
<button class="button-name" @click="changeAfter">判断修改</button>
</div>
</template>
<script>
export default {
name: 'ClassInfo',
data(){
return{
className:''
}
},
methods:{
changeName(){
// 功能1-第一步:先调用dispatch调用actions里面的getName方法,把修改后的名字传过去。
this.$store.dispatch('getName',this.className);
},
changeAfter(){
// 功能2-第一步:先调用dispatch调用actions里面的getChange方法,把修改后的名字传过去。
this.$store.dispatch('getChange',this.className);
}
}
}
</script>
<style lang="less">
.button-name{
margin-top: 10px;
margin-right: 10px;
}
</style>
store配置文件:index.js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 使用Vuex
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {
// 功能1-第二步。方法里面有两个参数,第一个是上下文,第二个是传过来的值。
getName(context,value){
console.log(context,value);
// commit。调用mutations里面的方法。
context.commit('getNameCommit',value);
},
// 功能2-第二步。判断当前是否为A班级,如果不是再使用commit调用mutations里面的方法。
getChange(context,value){
if(context.state.className !== 'A班级'){
context.commit('getChangeAfter',value)
}else{
alert('当前是A班级,不能修改!');
}
}
}
// 准备mutations-用于操作数据(state)
const mutations = {
// 功能1-第三步。方法里面有两个参数,第一个是state,第二个是传过来的值。
getNameCommit(state,value){
console.log(state,value);
state.className = value;
},
// 功能2-第三步。如果不是A班级,则调用该方法。
getChangeAfter(state,value){
state.className = value;
}
}
// 准备state-用于存储数据
const state = {
// 初始化
className:''
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
业务逻辑和发送请求等操作在actions中实现,在actions对象里面的方法有两个参数:context和value。
context为上下文,里面有commit和state等。
value为dispatch传过来的班级名字。
mutations对象里面的方法有两个参数:state和value。
state和Vuex里面state的值一样,但是是响应式的state,value为dispatch传过来的班级名字。
上面说了,业务逻辑和发送请求等操作在actions中实现,如果没有业务逻辑,像功能1一样直接操作数据,可直接使用commit调用mutations对象里面的方法。
班级组件:
<template>
<div>
<span>这是学校里面班级的信息,这里是{{$store.state.className || '--'}}班</span>
<div>
请输入修改后班级名字:<input type="text" v-model="className" placeholder="请输入班级名字"/>
</div>
<button class="button-name" @click="changeName">直接修改</button>
<button class="button-name" @click="changeAfter">判断修改</button>
</div>
</template>
<script>
export default {
name: 'ClassInfo',
data(){
return{
className:''
}
},
methods:{
changeName(){
// 功能1-第一步:直接commit调用mutations里面的getNameCommit方法,把修改后的名字传过去。
this.$store.commit('getNameCommit',this.className);
},
changeAfter(){
// 功能2-第一步:先调用dispatch调用actions里面的getChange方法,把修改后的名字传过去。
this.$store.dispatch('getChange',this.className);
}
}
}
</script>
<style lang="less">
.button-name{
margin-top: 10px;
margin-right: 10px;
}
</style>
store配置文件:index.js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 使用Vuex
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {
// 功能2-第二步。判断当前是否为A班级,如果不是再使用commit调用mutations里面的方法。
getChange(context,value){
if(context.state.className !== 'A班级'){
context.commit('getChangeAfter',value)
}else{
alert('当前是A班级,不能修改!');
}
}
}
// 准备mutations-用于操作数据(state)
const mutations = {
// 功能1-第二步。直接调用方法。
getNameCommit(state,value){
console.log(state,value);
state.className = value;
},
// 功能2-第三步。如果不是A班级,则调用该方法。
getChangeAfter(state,value){
state.className = value;
}
}
// 准备state-用于存储数据
const state = {
// 初始化
className:''
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
修改完后,在其他组件就可以查看或修改当前班级名字,并且信息都是同步的。
在组件中读取Vuex中的数据:
$store.state
组件中修改班级名字时,使用dispatch或commit调用相关方法就行。
组件中修改Vuex中的数据:
$store.dispatch('actions对象中的方法名',数据)
或
$store.commit('mutations对象中的方法名',数据)
其他组件:
<template>
<div>
这是学生组件:所在班级{{$store.state.className}}
</div>
</template>
<script>
export default {
name: 'StudentList',
}
</script>
<style lang="less">
</style>
简单的Vuex数据持久化存储
上面虽然可以多个组件共同操作一个数据,但是刷新页面数据就丢失了,如果想数据刷新不丢失,就需要Vuex数据持久化存储。比如登录状态、token等用户信息。
使用LocalStorage进行储存
第一种方法就是在state中使用localStorage进行储存。并且在mutations操作state时,也要使用localStorage保存修改后对应的值。
store配置文件:index.js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 使用Vuex
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {
// 功能2-第二步。判断当前是否为A班级,如果不是再使用commit调用mutations里面的方法。
getChange(context,value){
if(context.state.className !== 'A班级'){
context.commit('getChangeAfter',value)
}else{
alert('当前是A班级,不能修改!');
}
}
}
// 准备mutations-用于操作数据(state)
const mutations = {
// 功能1-第二步。直接调用方法。
getNameCommit(state,value){
console.log(state,value);
state.className = value;
// 使用localStorage存储更新后的值
localStorage.setItem('className',state.className);
},
// 功能2-第三步。如果不是A班级,则调用该方法。
getChangeAfter(state,value){
state.className = value;
// 使用localStorage存储更新后的值
localStorage.setItem('className',state.className);
}
}
// 准备state-用于存储数据
const state = {
// Vuex初始化的时候我们就先用localStorage里面读取之前的数据,并存储在state中
className: localStorage.getItem('className')
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
使用插件
步骤:
安装插件->store配置文件:index.js导入插件->Vuex.Store中配置plugins使用插件。
直接使用Vue的插件实现:
npm install vuex-persistedstate --save
store配置文件:index.js
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 引入持久化存储插件
import persistedstate from 'vuex-persistedstate'
// 使用Vuex
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {
// 功能2-第二步。判断当前是否为A班级,如果不是再使用commit调用mutations里面的方法。
getChange(context,value){
if(context.state.className !== 'A班级'){
context.commit('getChangeAfter',value)
}else{
alert('当前是A班级,不能修改!');
}
}
}
// 准备mutations-用于操作数据(state)
const mutations = {
// 功能1-第二步。直接调用方法。
getNameCommit(state,value){
console.log(state,value);
state.className = value;
},
// 功能2-第三步。如果不是A班级,则调用该方法。
getChangeAfter(state,value){
state.className = value;
}
}
// 准备state-用于存储数据
const state = {
className: ''
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
// 使用持久化插件
plugins:[
persistedstate({
// storage 存储方式 默认的是localStorage存储,可以修改成会话存储(window.sessionStorage)
storage:window.localStorage
})
]
})
因为默认的是localStorage存储,所以当localStorage存储时,可简写:
plugins:[persistedstate()]
使用以上方法时,全部数据都是持久化存储,若只想某些数据持久化存储,就需要设置一些配置。比较全的配置如下,设置plugins:
// 该文件用于创建Vuex中最为核心的store
// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 引入持久化存储插件
import persistedstate from 'vuex-persistedstate'
// 使用Vuex
Vue.use(Vuex)
// 准备actions-用于响应组件中的动作
const actions = {
// 功能2-第二步。判断当前是否为A班级,如果不是再使用commit调用mutations里面的方法。
getChange(context,value){
if(context.state.className !== 'A班级'){
context.commit('getChangeAfter',value)
}else{
alert('当前是A班级,不能修改!');
}
}
}
// 准备mutations-用于操作数据(state)
const mutations = {
// 功能1-第二步。直接调用方法。
getNameCommit(state,value){
console.log(state,value);
state.className = value;
},
// 功能2-第三步。如果不是A班级,则调用该方法。
getChangeAfter(state,value){
state.className = value;
}
}
// 准备state-用于存储数据
const state = {
className: '',
studentName: ''
}
// 创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
// 使用持久化插件
plugins:[persistedstate({
storage: window.sessionStorage,
reducer(state){
return{
// 只存储state中的className
className:state.className
}
}
})]
})
可在浏览器查看存储的数据: