• VueX的基本使用


    VueX的基本使用

    1、什么是VueX

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    以上是官方文档的介绍,我浅显的理解VueX就是用于存储一些全局配置,可以在不同的组件中使用这些全局配置,根据不同的使用场景提供了异步获取和计算属性式获取的方式。

    2、VueX的使用场景

    传统传值方式:

    VueX传值方式:

    从上图我们可以看出,使用VueX后,组件之间值的传递变的异常简单。可以进行统一管理,统一使用。减少了请求后台的次数。没有了繁琐的props和$refs。

    但是VueX也有他的弊端,例如刷新页面后state将会变为初始状态,对于频繁变化的结果也不适于存储在VueX内,因此不建议将所有状态都使用VueX来管理,否则你需要在每个使用的页面都调用一次actions(代码分层的方式除外)。

    VueX最常见的使用场景就是存储用户的信息、保存token、主题配置等。一种更加高级的用法是使用VueX将和后端交互的axios异步请求进行封装,实现代码的分层,让组件中的代码更加关注与页面交互

    3、quickstart

    安装vuex

    npm install vuex --save
    

    在根目录创建store目录,在目录内创建index.js,在其内部创建

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {},
      mutations: {},
      actions: {},
      modules: {}
    })
    

    在main.js内引用store

    import Vue from 'vue'
    import App from './App.vue'
    import router from './router' //重要
    import store from './store'  //重要
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css'
    
    Vue.use(ElementUI)
    Vue.config.productionTip = false
    
    new Vue({
      router, 
      store, //重要
      render: h => h(App)
    }).$mount('#app')
    

    如果使用脚手架创建项目,且默认选择了vuex,系统会自动为我们创建上述内容。

    4、state

    4.1、state介绍

    VueX中的state就是真正保存数据的地方,它的写法和作用类似于vue对象内的data。

    • state内存放的数据如果发生了修改,依赖这个属性的组件的数据也会发生变化。
    • state内的属性无法直接修改,必须通过mutations修改。
    • state内可以存储一般数据类型,也可以存储对象类型。

    4.2、在state内添加一些数据

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        title: 'hello world',
        userInfo: {
          name: 'rayfoo',
          age: 24,
          car: ['Porsche', 'BMW']
        }
      },
      mutations: {},
      actions: {},
      modules: {}
    })
    

    4.3、在页面中使用state

    // 在.vue内使用
    <h1 v-text="$store.state.title"></h1>
    {{$store.state.title}}
    
    // 在js中使用
    this.$store.state.title
    

    4.4、语法糖...mapState

    为了简化state的访问方式,VueX提供了访问语法糖,可以像访问当前项目计算属性一样访问state。

    import { mapState } from 'vuex'
    export default {
      computed: {
        ...mapState(['title'])
      }
    }
    

    页面调用

    <h1 v-text="title"></h1>
    

    5、mutations

    5.1、mutations介绍

    前面我们介绍了,state内的数据是无法直接修改的。如果要修改state内的元素,必须使用mutations。如果你学过java语言,那么可以用setter方法来简单的理解mutations。mutations的存在就是为了修改state内的数据。

    由于mutations和我们下面要说的actions使用时非常相似,所以mutations的名称通常用大写加下划线表示

    4.2、声明mutations

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        title: 'hello world'
      },
      mutations: {
        SET_TITLE (state, _title) {
          state.title = _title
        }
      },
      actions: {},
      modules: {}
    })
    
    

    我们可以看到,mutations的写法类似于method,它的第一个参数是固定的state,表示要修改的state。后面的参数我们可以自由指定或者省略。

    上面的案例中我们通过setTitle将state内的title修改为了新的title,而新的title可以由参数的形式传递进来。

    4.3、调用mutations

    上面的案例,我们创建了一个mutations,它只是一个声明的过程,如果我们需要调用,则需要使用下面的代码:

    this.$store.SET_TITLE("setTitle","hello Vuex")
    

    4.4、语法糖...mapMutations

    使用this.$store.commit这种操作形式过于繁琐,mutations提供了语法糖,能更像调用当前页面的methods一样对其调用。

    用法如下

    <script>
    import { mapMutations } from 'vuex'
    export default {
      created () {
        // 使用setTitle
        this.SET_TITLE('你好,mapMutations')
      },
      methods: {
        ...mapMutations(['SET_TITLE'])
      }
    }
    </script>
    

    6、getters

    6.1、getters介绍

    前面我们用java中的setter比喻了mutations,那getters也可以比喻为java中的getter方法。如果没学过java也没关系,你一定用过Vue中的计算属性computed,getters的用法就类似于computed。

    getters可以单纯的获取state中的内容,也可以对结果做过滤、计算、截取等等一系列的操作,来拿到我们需要的结果。

    getters默认是不支持参数的,我们可以通过返回一个函数的形式来完成参数的传递。

    6.2、声明getters

    下面的案例我们通过getter,将所有的title以加上书名号的形式返回:

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        title: 'hello world'
      },
      mutations: {},
      actions: {},
      getters: {
        getFomatTitle (state) {
          return `《${state.title}》`
        }
      },
      modules: {}
    })
    
    

    6.3、使用getters

    //.vue页面内
    $store.getters.getFomatTitle
    
    // javascript
    this.$store.getters.getFomatTitle
    

    6.4、向getters传递参数

    下面的案例演示了通过返回函数的形式向getters内传递参数

    声明

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        studentList: [
          { id: 1, name: 'zhangsan' },
          { id: 2, name: 'lisi' },
          { id: 3, name: 'wangwu' }
        ]
      },
      mutations: {},
      actions: {},
      getters: {
        getStudentById: state => id => {
          return state.studentList.find(student => student.id == id)
        }
      },
      modules: {}
    })
    
    

    调用

    this.$store.getters.getStudentById(1)
    

    4.5、语法糖...mapGetters

    和mutations意义,getters也拥有自己的语法糖,下面的案例演示了如何使用getters的语法糖

    import { mapGetters } from 'vuex'
    export default {
      computed: {
        ...mapGetters(['getFomatTitle', 'getStudentById'])
      }
    }
    

    通过...mapGetters引入后,就可以像使用当前组件中的计算属性一样使用VueX的getters了。

    页面使用

    <h3 v-text="student.name"></h3>
    <h3 v-text="getStudentById(2).name"></h3>
    

    7、actions

    7.1、actions介绍

    actions可以理解为mutations的异步版本,由于修改state内的数据必须使用mutations,所以actions内还是必须使用mutations的。

    7.2、声明actions

    在vue里最常见的异步操作就是调用axios请求,下面我们通过一个actions调用axios的案例来认识一下它。

    import Vue from 'vue'
    import Vuex from 'vuex'
    import axios from 'axios'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        title: 'hello world'
      },
      mutations: {
        SET_TITLE (state, _title) {
          state.title = _title
        }
      },
      actions: {
        setAsyncTitle (context, title) {
          axios.get(`/api/get-title?title=${title}`).then(resp => {
            context.commit('SET_TITLEX', resp.data)
          })
        }
      },
      getters: {},
      modules: {}
    })
    
    

    7.3、使用actions

    this.$store.dispatch('setAsyncTitle', '你好,Axios!!!')
    

    7.4、语法糖...mapActions

    import { mapActions } from 'vuex'
    export default {
      created () {
        this.setAsyncTitle('你好,Axios!!!')
      },
      methods: {
        ...mapActions(['setAsyncTitle'])
      }
    }
    

    8、modules

    8.1、modules介绍

    前面的案例我们都是在VueX自动生成的./store/index.js中编写的,真实的项目中,VueX中保存的内容会很多,保存在一个文件中会很难管理,通过modules可以更方便的管理VueX。

    每个module都可以拥有自己的state、mutations、getters、actions。

    在实际开发中,modules中通常不会包含getters,而是单独创建一个js来保存VueX中的所有getters

    8.2、modules的使用

    简单的使用形式:

    const moduleA = {
      state: () => ({ ... }),
      mutations: { ... },
      actions: { ... },
      getters: { ... }
    }
    
    const moduleB = {
      state: () => ({ ... }),
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        a: moduleA,
        b: moduleB
      }
    })
    
    store.state.a // -> moduleA 的状态
    store.state.b // -> moduleB 的状态
    

    8.3、多文件形式引用Modules

    多文件的引用形式:以下代码引用自ruoyi-vue

    module

    import { login, logout, getInfo } from '@/api/login'
    import { getToken, setToken, removeToken } from '@/utils/auth'
    
    const user = {
      state: {
        token: getToken(),
        name: '',
        avatar: '',
        roles: [],
        permissions: []
      },
    
      mutations: {
        SET_TOKEN: (state, token) => {
          state.token = token
        },
        SET_NAME: (state, name) => {
          state.name = name
        },
        SET_AVATAR: (state, avatar) => {
          state.avatar = avatar
        },
        SET_ROLES: (state, roles) => {
          state.roles = roles
        },
        SET_PERMISSIONS: (state, permissions) => {
          state.permissions = permissions
        }
      },
    
      actions: {
        // 登录
        Login({ commit }, userInfo) {
         // 略
        },
    
        // 获取用户信息
        GetInfo({ commit, state }) {
          // 略
        },
    
        // 退出系统
        LogOut({ commit, state }) {
          // 略
        },
    
        // 前端 登出
        FedLogOut({ commit }) {
          return new Promise(resolve => {
            commit('SET_TOKEN', '')
            removeToken()
            resolve()
          })
        }
      }
    }
    
    export default user
    
    

    getters

    const getters = {
      sidebar: state => state.app.sidebar,
      size: state => state.app.size,
      device: state => state.app.device,
      visitedViews: state => state.tagsView.visitedViews,
      cachedViews: state => state.tagsView.cachedViews,
      token: state => state.user.token,
      avatar: state => state.user.avatar,
      name: state => state.user.name,
      introduction: state => state.user.introduction,
      roles: state => state.user.roles,
      permissions: state => state.user.permissions,
      permission_routes: state => state.permission.routes,
      topbarRouters:state => state.permission.topbarRouters,
      defaultRoutes:state => state.permission.defaultRoutes,
      sidebarRouters:state => state.permission.sidebarRouters,
    }
    export default getters
    
    

    index.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    import app from './modules/app'
    import user from './modules/user'
    import tagsView from './modules/tagsView'
    import permission from './modules/permission'
    import settings from './modules/settings'
    import getters from './getters'
    
    Vue.use(Vuex)
    
    const store = new Vuex.Store({
      modules: {
        app,
        user,
        tagsView,
        permission,
        settings
      },
      getters
    })
    
    export default store
    
    

    使用

    // state and getters
    this.$store.state.模块名.state
    
    // actions
    this.$store.dispatch('模块名/actionsName',prams)
    
    // mutations 由于mutations不区分模块,所以注意命名全局唯一性
    this.$store.commit("mutationsName", params);
    
    // 因为上面说了 getters没有在每个modules内都写,所以可以直接用
    this.getters.gettersName
    
    // 如果使用module内的getters
    this.$store.getters["模块名/gettersName"]
    

    8.4、模块中的内容使用...mapXXX

    # state
    ...mapState({
      userName: state => state.user.name,
      userAge: state=> state.user.age
    })
    
    # mutations getters actions 没有命名空间的限定,所以要保证全局的唯一性
    ...mapMutations(['mutationsName'])
    ...mapGetters(['gettersName'])
    ...mapActions(['actionsName'])
    

    9、刷新页面数据丢失问题

    虽然VueX可以保存全局状态,但页面刷新后。VueX中的状态会被重新初始化。如果当前页面的值恰好是在其他组件内mutations或actions后产生的,那值可能会显示异常,造成数据丢失的感觉。例如如果把获取用户信息的操作放在了登录页面,那么进入系统后刷新就会发生上述情况。

    解决办法有如下三种思路:

    1、将vuex中的数据保存到浏览器缓存中如(cookie、localStorage和sessionStorage)。

    2、在会发生数据丢失的页面重新发送actions、mutations请求。

    方法1的缺点是不安全且不适用于大量数据的存储,方法2适用于少量数据且接口访问速度比较快的情况。所以有了方案3,方案3就是方案1和方案2的结合。

    3、页面刷新的时候异步请求后台数据,然后动态更新vuex中的数据,其中会有一种情况就是,网络延迟、数据量大的问题。此时还没等vuex获取到后台返回的数据,页面就已经加载完成了,这样就会造成数据丢失。所以该解决方案就是,监听浏览器刷新前事件,在浏览器刷新之前就把vuex里的数据保存至sessionStorage中,刷新成功后如果异步请求的数据还没返回则直接获取sessionStorage里的数据,否则获取vuex里的数据。(只有刷新后还没取到后台数据,才会从sessionStorage里取。确保数据的安全性,就算获取sessionStorage里的数据也是安全的,因为每次刷新都会重新赋值,不必担心数据被篡改问题,其次就是对sessionStorage里的数据做了加密操作)

    参考:

    VueX官方文档

    什么是vuex?怎么使用?在那种场景下使用

    如何解决vuex页面刷新数据丢失问题?

  • 相关阅读:
    sonarque下载和安装使用
    npm install appium
    WIn10 电脑运行Docker
    AngularJs Type error : Cannot read property 'childNodes' of undefined
    Angular ui-route介绍
    Thymeleaf的模板使用介绍
    IntelliJ IDEA IDEA 2018 激活注册码
    session和cookies
    springmvc中的拦截器interceptor用法
    实现mapper接口注入的两种方式,以及后台的使用区别
  • 原文地址:https://www.cnblogs.com/zhangruifeng/p/15631222.html
Copyright © 2020-2023  润新知