VueX讲解

一、VueX是什么,怎么使用,怎么调试。

  1. Vuex 是一个专为 .js 应用程序开发的状态管理模式,它由五部分组成
  2. vuex分为五个大块

    state: 统一定义公共数据(类似于data(){return {a:1, b:2,xxxxxx}})

    mutations : 使用它来修改数据(类似于methods)

    getters: 类似于computed(计算属性,对现有的状态进行计算得到新的数据-------派生 )

    actions: 发起异步请求

    modules: 模块拆分

  3. 用法:

在store下的index.js文件中

import Vue from 'vue'
import Vuex from 'vuex'
​
Vue.use(Vuex)
​
const store = new Vuex.Store({
  state(){
    return {
      // 就是公共的数据,所有的组件都可以直接使用
      count: 100
    }
  }
})
export default store

在main.js中

//...
import store from "./store"; //引入store
//....

new Vue({
  el: '#app',
  // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
  store,//可以在其他页面使用$store调用
  render: h => h(App)
};

高级用法(语法糖)

为保证页面数据刷新数据不丢失首先要安装数据持久化插件

yarn install vuex-persistedState -S

用法

import createPersistedState from 'vuex-persistedstate'

const store = new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  plugins: [createPersistedState({
    storage: sessionStorage,
    key: "token"
  })]//会自动保存创建的状态。刷新还在
})

高级用法—辅助函数(语法糖)


有4中分别是
mapState,mapActions,mapMutations,mapGetters
辅助函数可以把vuex中的数据和方法映射到vue组件中。达到简化操作的目的

如何使用在组件内引入

<template>
 <div id="">
   {{ token }}
   {{ token - x }}
 </div>
</template>

<script>
//首先使用import引入到vuex
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'

import {createNamespacedHelpers} from 'vuex'

const {mapState:mapStateUser,mapActions:mapActionUser,mapMutations:mapMutaionuser} = createNamespacedHelpers('user')

const {mapState:mapStateCart,mapActions:mapActionCart,mapMutations:mapMutaionCart} = createNamespacedHelpers('cart')



export default {
 name: '',
 data() {
   return {}
 },
 computed: {
   ...mapState({
     token: 'token'
   }),
   //使用的话直接使用展开
   ...mapGetters(['token-x']),
   ...mapSateUser(['userid']),
   ...mapStateCart({cartid:'userid'})
 },
 //生命周期 - 创建完成(访问当前this实例)
 created() {
   this.setToken('123456')
 },
 //生命周期 - 挂载完成(访问DOM元素)
 mounted() {},
 methods: {
   ...mapActions({
     setToken: 'setToken'
   }),
   ...mapMutations(['SET_TOKEN']),
   ...mapMutaionUser({
   setId:"setToken"
  })
 }
}
</script>

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

将不同模块进行分割(/src/store/index.js)

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

//用户模块
const userInfo = {
  namespaced: true, //开启命名空间
  state: {},
  actions: {},
  mutations: {},
  getters: {};

const goodsInfo = {
  namespaced: true, //开启命名空间
  state: {},
  actions: {},
  mutations: {},
  getters: {}
};

export default new Vuex.Store({
  modules: {
    userAbout: userInfo, //当前模块的命名空间: 模块数据
    goodsAbout: goodsInfo
  }
});

开启命名空间后,组件中读取state数据

//方式一:this.$store.getters['命名空间/getters中的方法名']
this.$store.getters['userAbout/userCount']
//方式二:...mapGetters('命名空间', ['getters中的方法名'])
...mapGetters('goodsAbout', ['goodsCount'])

开启命名空间后,组件中调用getters中的方法:

//方式一:this.$store.getters['命名空间/getters中的方法名']
this.$store.getters['userAbout/userCount']
//方式二:...mapGetters('命名空间', ['getters中的方法名'])
...mapGetters('goodsAbout', ['goodsCount'])

开启命名空间后,组件中调用actions中的方法

//方式一:this.$store.dispatch('命名空间/方法名', 参数)
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:...mapActions('命名空间', {'当前组件希望使用的名字':'actions中的方法的名字'})
...mapActions('goodsAbout', {addGoods: 'addGoods'}),

开启命名空间后,组件中调用mutations中的方法

//方式一://调用mutations中的方法:this.$store.commit('命名空间/方法名', 参数)
 this.$store.commit('userAbout/getUserInfoByName', this.userName)
//方式二://调用Mutations的方法:...mapMutations('命名空间', {'当前组件希望使用的名字':'mutations中的方法的名字'})
...mapMutations('goodsAbout', {getGoodsInfo: 'getGoodsInfoByName'})

二、什么情况下适合用VueX

如果不是大型单页应用,使用 Vuex 可能是繁琐冗余的。如果您的应用够简单,最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。

但是,如果需要构建一个中大型单页应用,就需要考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。

站在系统架构的角度上来,vuex虽然能很好帮助我们管理状态, 但随之也带来更多的概念让我们花时间来消化,总而言之,根据项目的实际大小来决定是否需要引入Vuex

三、核心概念理解

[1]. Actions 异步操作 

Actions更倾向于整合多个mutation操作

若没有网络请求或其他业务逻辑,组件中可以越过actions,即不写dispatch,直接调用mutations中的方法。

actions属性中的方法有一个默认的参数:context,context是和store对象具有相同方法和属性的对象,但是注意, 这里它们并不是同一个对象。所以可以使用contenxt.commit调用一个mutation中的方法或者通过context.state和context.getters来获取state的值和getters中的方法,当然也可以使用context.dispatch调用Actions中的方法。

在组件中使用this.$store.dispatch(‘actions中的方法’, ‘传递的参数’)来调用actions中的方法。

[2]. Mutations 状态更新

  • ①. mutations中的方法是Vuex中唯一可以操作State的方式。
  • ②. mutations 中的方法默认有一个参数state
  • ③. 在组件中使用 commit 调用mutations 中的方法

[3]. State (单一状态树)

英文名称是Single Source of Truth (SSOT),也可以翻译成单一数据源。

所有状态要放在一个store,整个项目要只有一个store

Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新
这就要求我们必须遵守一些Vuex对应的规则:
1). 提前在store中初始化好所需的属性.

2).当给state中的对象添加新属性时, 使用下面的方式:
- 方式一: 使用Vue.set(‘被添加属性的对象’, ‘新属性名’, ‘属性值’)
- 方式二: 用新对象给旧对象重新赋值

3). 删除state中的对象属性
Vue.delete(“对删除的属性对象”, “被删除的属性名”);

[4]. getters 获取状态

getters相当于store的computed(计算属性),getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

getters中第一个的参数是state,这个参数就是store中的state属性,可以利用这个参数来获取store中state的属性值

getters中第二个参数是getters,这个参数getters本身,可以利用这个参数来获取getters中的其他方法。 

getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数。

四、js中如何使用vuex变量

在js文件中直接store.xx.xx获取就可以了,JS文件没得this,上面肯定没有$store。

五、如何解决 Vuex 页面刷新数据丢失问题?

1、问题描述:

一般在登录成功的时候需要把 用户信息 ,菜单信息 放置 Vuex 中 ,作为全局的共享数据。

但是在页面刷新的时候 Vuex 里的数据会重新初始化 ,导致数据丢失 。

因为 Vuex 里的数据是保存在运行内存中的 ,当页面刷新时 ,页面会重新加载 Vue 实例 ,

Vuex 里面的数据就会被重新赋值 。

2、解决思路:
办法一:将 Vuex 中的数据直接保存到浏览器缓存中

(sessionStorage、localStorage、cookie)

办法二:在页面刷新的时候再次请求远程数据 ,使之动态更新 Vuex 数据

办法三:在父页面向后台请求远程数据 ,并且在页面刷新前将 Vuex 的数据

先保存至 sessionStorage(以防请求数据量过大页面加载时拿不到返回的数据)

分析:

办法一的缺点是不安全 ,不适用大数据量的存储;

办法二适用于少量的数据 ,并且不会出现网络延迟;

办法三是要讲的重点 ,办法二和办法一 一起使用。

3、使用持久化插件

@2 vuex-persistedstate

原理:

将 Vuex 的 state 存在 localStorage 或 sessionStorage 或 cookie 中一份

刷新页面的一瞬间,Vuex 数据消失 ,Vuex 会去 sessionStorage 中拿回数据 ,

变相的实现了数据刷新不丢失 ~

使用方法:

安装:$  npm install vuex-persistedstate --save 

在 store 下的 index.js 中 ,引入并配置
 


import createPersistedState from "vuex-persistedstate"
 
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()]
})

此时可以选择数据存储的位置 ,可以是 localStorage / sessionStorage / cookie ,

此处以存储到 sessionStorage 为例 ,配置如下:


import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage
  })]
})

存储指定 state:

vuex-persistedstate 默认持久化所有 state ,指定需要持久化的 state , 配置如下:


import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage,
      reducer(val) {
          return {
          // 只储存state中的user
          user: val.user
        }
     }
  })]

此刻的 val 对应 store / modules 文件夹下几个 js 文件存储的内容 ,

也就是 store / index 中 import 的几个模块 ,可以自己打印看看。

希望哪一部分的数据持久存储 ,将数据的名字在此配置就可以,

目前我只想持久化存储 user 模块的数据 。

注意:如果此刻想配置多个选项,将 plugins 写成一个一维数组,不然会报错。
 

import createPersistedState from "vuex-persistedstate"
import createLogger from 'vuex/dist/logger'
// 判断环境 vuex 提示生产环境中不使用
const debug = process.env.NODE_ENV !== 'production'
const createPersisted = createPersistedState({
  storage: window.sessionStorage
})
export default new Vuex.Store({
 // ...
  plugins: debug ? [createLogger(), createPersisted] : [createPersisted]
})

@3 vuex-along

将  state  里的数据保存一份到本地存储

( localStorage、sessionStorage、cookie )

// App.vue

<script>
    export default{
        created() {
            //在页面加载时读取sessionStorage里的状态信息
             if (sessionStorage.getItem("store") ) {
                this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem("store"))))
            }
 
            //在页面刷新时将vuex里的信息保存到sessionStorage里
            window.addEventListener("beforeunload",()=>{
                sessionStorage.setItem("store",JSON.stringify(this.$store.state))
            })
        }
    }
</script>

2、使用第三方插件如 vuex-along

( 本质上还是利用 session 等缓存到本地 )

import Vue from 'vue'
import Vuex from 'vuex'
import VueXAlong from 'vuex-along'
Vue.use(Vuex)
let productData = require('@/assets/api/list.json')
 
const moduleA = {
    state: {
        a1: 'a1',
        a2: 'a2',
    }
}
export default new Vuex.Store({
    state: {
        productList: [],//列表数据
        cartList: [],//购物车数据
    },
    mutations: {
        //产品列表
        setProductList(state, data){
            state.productList = data
        },
        //加入购物车
        setCartList(state, id){
            let  cartIndex = state.cartList.findIndex(item => item.id === id)
            if(cartIndex < 0){
                state.cartList.push({id, count: 1})
            }else{
                state.cartList[cartIndex].count++
            }
        },
        //删除购物车商品
        deleteCartList(state, id){
            let  cartIndex = state.cartList.findIndex(item => item.id === id)
            state.cartList.splice(cartIndex, 1)
        },
        //编辑购物车商品数量
        editCartList(state, data){
            let cartIndex = state.cartList.findIndex(item => item.id === data.id)
            state.cartList[cartIndex].count = data.count
        },
        clearCart(state){
            state.cartList = []
        },
    },
    actions: {
        getProductList(context){
            //模拟ajax请求,将返回的信息直接存储在store
            setTimeout(()=>{
                context.commit('setProductList', productData)
            }, 2000)
        },
        buy(context){
            //模拟ajax请求通过返回promise对象将结果返回给操作提交的地方
            return new Promise((resolve, reject) => {
                setTimeout(()=>{
                    context.commit('clearCart')
                    resolve({msg:'下单成功', code: 200})
                    //reject({message: '提交失败', code: 300})
                }, 1000)
            })
        }
    },
    modules: {
        ma: moduleA
    },
    //缓存state的数据到storage
    plugins: [VueXAlong()],
    //全量的参数配置(sessionStorage 数据恢复优先级高于 localStorage)
    /* plugins: [VueXAlong({
        // 设置保存的集合名字,避免同站点下的多项目数据冲突
        name: 'my-app-VueXAlong',
        //过滤ma的数据将其他的数据存入localStorage
        local: {
            list: ['ma'],//需要监听的属性名或者模块名
            isFilter: true,//是否过滤而非保存
        },
        //保存ma的a1数据到sessionStorage
        session: {
            list: ['ma.a1'],
            isFilter: false,
        },
        //仅使用sessionStorage保存
        //justSession: true,
    })] */

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值