Vuex和Vuex数据持久化储存

516 阅读6分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

Vuex简介

Vuex是在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个应用组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

Vuex的使用场景:

1.多个组件依赖于同一个状态。

2.来自不同组件的行为需要变更同一状态。

Vuex的原理图(官网):

image.png

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:

image.png

业务逻辑和发送请求等操作在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等。

image.png

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
            }
        }
    })]
})

可在浏览器查看存储的数据:

image.png