• Vue3路由守卫、vuex的使用、vuex模块化拆分、vite中自动导入模块文件



    1. 路由守卫

    vue3 中的导航守卫与 vue2 中的基本一致,不同的地方在于,vue3 中导航守卫取消了 next 参数,而是通过返回 false 来取消路由跳转。

    以前置路由守卫为例,结合 sessionStorage 实现获取 token 值之后跳转到后台管理页面。

    配置路由及守卫:

    // vue-router中提供3种的路由模式
    import { createWebHistory, createRouter } from 'vue-router'
    
    const routes = [
      {
        path: '/login',
        component: () => import('@/views/login.vue')
      },
      {
        path: '/admin',
        component: () => import('@/views/admin.vue'),
        meta: {
          isLogin: true
        }
      }
    ] 
    
    const router = createRouter({
      // 路由的模式
      history: createWebHistory(),
      // 路由规则
      routes
    })
    
    // 全局前置守卫
    router.beforeEach((to, from) => {
      // 验证指定的页面无须登录就可以访问
      // 1.可以通过path路由来区别
      // 2.meta来完成区别
      // console.log('前置全局守卫', to.path);
      // console.log('前置全局守卫', to.meta.isLogin);
      // 如果此页面需要登录才能访问到,就需要来判断当前的本地存储中是否有token
      if (!to.meta.isLogin) {
        return true
      }
      // 如下的页面一定要求用户登录才能访问到
      if (!sessionStorage.getItem('token')) {
        // 跳转到登录页
        // return '/login'
        // 跳转后不能回退
        return { path: '/login', replace: true }
      }
    
      return true
    })
    
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    mock 假数据:

    import Mockjs from 'mockjs'
    
    const mockData = [
      {
        url: '/api/login',
        method: 'post',
        response: () => ({
          code: 0,
          msg: 'ok',
          data: {
            uid: 1000,
            nickname: '张三',
            token: 'afewlfjewlfjewlfejlfejl;fejlf;e'
          }
        })
      }
    ]
    
    export default mockData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    登录页:

    <template>
      <div>
        <h3>登录页面h3>
        <div>
          <input type="text" v-model="username" />
        div>
        <div>
          <input type="text" v-model="password" />
        div>
        <div>
          <button @click="doLogin">进入系统button>
        div>
      div>
    template>
    
    <script setup>
    import { reactive, toRefs } from 'vue'
    import { useRouter } from 'vue-router'
    import { doLoginApi } from '@/api/userApi'
    
    const router = useRouter()
    
    const state = reactive({
      username: '',
      password: ''
    })
    const { username, password } = { ...toRefs(state) }
    
    // 登录成功
    const doLogin = async () => {
      let ret = await doLoginApi(state)
      let token = ret.data.token
      sessionStorage.setItem('token', token)
      router.replace('/admin')
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    后台管理页:

    <template>
      <div>
        <h3>后台管理h3>
      div>
    template>
    
    <script setup>
    
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    2. vuex的使用

    2.1 基本使用

    安装:

    yarn add vuex
    
    • 1

    使用:

    首先为 vuex 创建 store 目录(store/index.js):

    import { createStore } from 'vuex'
    
    // const store = createStore({
    //   state: {
    //     num: 100
    //   }
    // })
    
    // 如果你现在用的是基于vue的服务器端渲染,此时一定要写成回调函数方案
    const store = createStore({
      state: () => ({
        num: 100
      }),
      mutations: {
        setNum(state, payload) {
          state.num += payload
        }
      },
      actions: {
        asyncSetNum({ commit }, payload) {
          setTimeout(() => {
            commit('setNum', payload)
          }, 1000);
        }
      }
    })
    
    export default store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在入口文件(main.js)处引入 vuex:

    // 创建vue入口程序,由原来的类实例,变成现在的函数方式,为了更好在打包时优化代码
    import { createApp } from 'vue'
    // 根组件
    import App from './App.vue'
    // 路由
    import router from './router'
    // vuex
    import store from './store'
    
    import createGlobalComponent from './components'
    import globalProperties from './config/globalProperties'
    
    // 实例化一个Vue顶层组件
    // const app = createApp(App)
    
    // 创建全局组件
    // // createGlobalComponent(app)
    // app.use(createGlobalComponent)
    // app.use(globalProperties)
    // // 路由
    // app.use(router)
    // // vuex
    // app.use(store)
    // app.mount('#app')
    
    // 工作中常用写法:
    createApp(App)
      .use(createGlobalComponent)
      .use(globalProperties)
      .use(router)
      .use(store)
      .mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    关于页面:

    <template>
      <div>
        <h3>关于页面 -- {{ num }}h3>
        <button @click="setNum">++同步++button>
        <button @click="asyncSetNum">++异步++button>
      div>
    template>
    
    <script setup>
    import { computed } from 'vue'
    // vuex提供hook函数
    import { useStore } from 'vuex'
    const store = useStore()
    
    const num = computed(() => store.state.num)
    
    const setNum = () => {
      store.commit('setNum', 1)
    }
    
    const asyncSetNum = () => {
      store.dispatch('asyncSetNum', 2)
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    2.2 模块化拆分

    方式一

    store/modules/count.js:

    export default {
      // 开启强制命名空间
      namespaced: true,
      state: () => ({
        num: 100
      }),
      mutations: {
        setNum(state, payload) {
          state.num += payload
        }
      },
      actions: {
        asyncSetNum({ commit }, payload) {
          setTimeout(() => {
            commit('setNum', payload)
          }, 1000);
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    store/modules/user.js:

    export default {
      // 开启强制命名空间
      namespaced: true,
      state: () => ({
        uid: 0,
        nickname: '',
        token: ''
      }),
      mutations: {
        login(state, payload) {
          state.uid = payload.uid
          state.nickname = payload.nickname
          state.token = payload.token
          sessionStorage.setItem('token', payload.token)
        }
      },
      actions: {
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    store/index.js:

    import { createStore, useStore } from 'vuex'
    
    import count from './modules/count'
    import user from './modules/user'
    
    // 如果你现在用的是基于vue的服务器端渲染,此时一定要写成回调函数方案
    const store = createStore({
      modules: {
        count,
        user
      }
    })
    
    export default store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    关于页面:

    <template>
      <div>
        <h3>关于页面 -- {{ num }}h3>
        <button @click="setNum">++同步++button>
        <button @click="asyncSetNum">++异步++button>
      div>
    template>
    
    <script setup>
    import { computed } from 'vue'
    // vuex提供hook函数
    // 方式一导入
    import { useStore } from 'vuex'
    const store = useStore()
    
    const num = computed(() => store.state.count.num)
    
    const setNum = () => {
      store.commit('count/setNum', 1)
    }
    
    const asyncSetNum = () => {
      store.dispatch('count/asyncSetNum', 2)
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    登录页面:

    <template>
      <div>
        <h3>登录页面h3>
        <div>
          <input type="text" v-model="username" />
        div>
        <div>
          <input type="text" v-model="password" />
        div>
        <div>
          <button @click="doLogin">进入系统button>
        div>
      div>
    template>
    
    <script setup>
    import { reactive, toRefs } from 'vue'
    import { useRouter } from 'vue-router'
    import { doLoginApi } from '@/api/userApi'
    
    //方式一导入
    import { useStore } from 'vuex'
    const store = useStore()
    
    const router = useRouter()
    
    const state = reactive({
      username: '',
      password: ''
    })
    const { username, password } = { ...toRefs(state) }
    
    // 登录成功
    const doLogin = async () => {
      let ret = await doLoginApi(state)
      let token = ret.data.token
      sessionStorage.setItem('token', token)
      router.replace('/admin')
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    在这里插入图片描述

    方式二

    对 store 的入口文件中模块的导出作修改(对 useStore 做二次封装后导出)、对登录页面模块的导入作修改。

    store/index.js:

    import { createStore, useStore } from 'vuex'
    
    import count from './modules/count'
    import user from './modules/user'
    
    // 如果你现在用的是基于vue的服务器端渲染,此时一定要写成回调函数方案
    const store = createStore({
      modules: {
        count,
        user
      }
    })
    
    // 方式二导出
    export const useUserStateStore = () => {
      let store = useStore()
      return [store.state.user, store.commit, store.dispatch]
    }
    
    export default store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    登录页面:

    <template>
      <div>
        <h3>登录页面h3>
        <div>
          <input type="text" v-model="username" />
        div>
        <div>
          <input type="text" v-model="password" />
        div>
        <div>
          <button @click="doLogin">进入系统button>
        div>
      div>
    template>
    
    <script setup>
    import { reactive, toRefs } from 'vue'
    import { useRouter } from 'vue-router'
    import { doLoginApi } from '@/api/userApi'
    
    //方式二导入
    import { useUserStateStore } from '@/store'
    const [userState, commit] = useUserStateStore()
    
    const router = useRouter()
    
    const state = reactive({
      username: '',
      password: ''
    })
    const { username, password } = { ...toRefs(state) }
    
    // 登录成功
    const doLogin = async () => {
      let ret = await doLoginApi(state)
      let token = ret.data.token
      commit('user/login', ret.data)
      router.replace('/admin')
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    方式三

    在方式二的基础上,将 store/index.js 文件中的方法,拆分开导入。

    store/index.js:

    import { createStore, useStore } from 'vuex'
    
    import count from './modules/count'
    import user from './modules/user'
    
    // 如果你现在用的是基于vue的服务器端渲染,此时一定要写成回调函数方案
    const store = createStore({
      modules: {
        count,
        user
      }
    })
    
    export const useUserState = () => {
      let store = useStore()
      return store.state.user
    }
    
    export const useCommit = () => {
      let store = useStore()
      return store.commit
    }
    
    export const useDispatch = () => {
      let store = useStore()
      return store.dispatch
    }
    
    export default store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    登录页面:

    <template>
      <div>
        <h3>登录页面h3>
        <div>
          <input type="text" v-model="username" />
        div>
        <div>
          <input type="text" v-model="password" />
        div>
        <div>
          <button @click="doLogin">进入系统button>
        div>
      div>
    template>
    
    <script setup>
    import { reactive, toRefs } from 'vue'
    import { useRouter } from 'vue-router'
    import { doLoginApi } from '@/api/userApi'
    
    const router = useRouter()
    
    const state = reactive({
      username: '',
      password: ''
    })
    const { username, password } = { ...toRefs(state) }
    
    // 登录成功
    const doLogin = async () => {
      let ret = await doLoginApi(state)
      let token = ret.data.token
      commit('user/login', ret.data)
      router.replace('/admin')
    }
    script>
    
    <style lang="scss" scoped>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    3. 在vite中自动导入模块文件

    import { createStore, useStore } from 'vuex'
    
    // 自动导入模块
    // eager 同步,不能使用 promise
    const moduleFiles = import.meta.glob('./modules/*', { eager: true })
    let modules = {}
    for (let key in moduleFiles) {
      let prop = /\.\/modules\/(\w+)\.js/.exec(key)[1]
      let value = moduleFiles[key].default
      modules[prop] = value
    }
    
    // 如果你现在用的是基于vue的服务器端渲染,此时一定要写成回调函数方案
    const store = createStore({
      modules
    })
    
    export const useUserState = () => {
      let store = useStore()
      return store.state.user
    }
    
    export const useCommit = () => {
      let store = useStore()
      return store.commit
    }
    
    export const useDispatch = () => {
      let store = useStore()
      return store.dispatch
    }
    
    export default store
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

  • 相关阅读:
    Windows系统配置CUDA编程环境
    【牛客编程题】Python机器学习(入门例题5题)
    记录一次木马排查
    (封装)已知的一个类Student
    CleanMyMac XMac苹果电脑专属系统优化工具
    【Python机器学习】零基础掌握EllipticEnvelope协方差估计
    【JAVA】String类
    华为7年经验的软件测试总监,给所有想转行学软件测试的同学的几个建议
    CSS3之转换(2D转换,动画,3D转换)
    【个人笔记js的原型理解】
  • 原文地址:https://blog.csdn.net/weixin_45605541/article/details/128035371