Vue.js 3如何防止已认证页面刷新时闪现登录页面
问题:Vue3刷新已认证页面时登录页面闪现的解决方法
原因分析
问题核心在于页面初始渲染时,Vuex的isLogin默认是未认证的false,而登录状态校验逻辑fetchUserLogin是在onMounted钩子中才执行。这就导致页面先渲染了login组件,等异步的登录校验完成后才切换到router-view,从而出现登录页面闪现的情况。另外当前路由守卫未做任何权限校验,直接放行所有路由,也会加剧这种问题。
解决方案
1. 改造App.vue:等待登录校验完成后再渲染内容
添加加载状态,避免初始阶段直接渲染登录组件,等登录状态确认后再展示对应内容。
修改后的App.vue:
<template> <!-- 校验未完成时显示加载态,阻断错误渲染 --> <div v-if="isCheckingLogin" class="loading">加载中...</div> <router-view v-else-if="store.state.isLogin"/> <login v-else></login> </template> <script setup lang="ts"> import Login from '@/components/Login.vue' import { useStore } from 'vuex'; import { ref, onBeforeMount } from "vue"; const store = useStore(); const isCheckingLogin = ref(true); // 提前到onBeforeMount执行,更早触发登录校验 onBeforeMount(async ()=>{ await store.dispatch('fetchUserLogin'); // 校验完成后关闭加载状态 isCheckingLogin.value = false; }); </script> <style scoped> .loading { display: flex; justify-content: center; align-items: center; height: 100vh; font-size: 18px; } </style>
2. 完善路由守卫:跳转前先校验登录状态
利用router.beforeEach在路由跳转前完成登录校验,同时处理不同路由的权限逻辑,避免未校验就进入页面。
修改后的router/index.ts:
import { createRouter, createWebHistory } from 'vue-router' import HomeView from '@/views/HomeView.vue' import Login from '@/components/Login.vue' // @ts-ignore import { store } from "@/vuex/store"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/login', name: 'login', component: Login, // 已登录用户访问登录页直接跳首页 meta: { requiresGuest: true } }, { path: '/home', name: 'home', component: HomeView, // 需要登录才能访问 meta: { requiresAuth: true } }, // 404路由重定向 { path: '/:pathMatch(.*)*', redirect: '/home' } ] }) router.beforeEach(async (to, from, next) => { // 首次进入/刷新时,先确认登录状态 if (store.state.isLogin === undefined || store.state.isLogin === null) { await store.dispatch('fetchUserLogin'); } // 拦截未登录用户访问需认证路由 if (to.meta.requiresAuth && !store.state.isLogin) { next({ name: 'login' }); } // 拦截已登录用户访问登录页 else if (to.meta.requiresGuest && store.state.isLogin) { next({ name: 'home' }); } // 其他情况正常放行 else { next(); } }) export default router
3. 优化Vuex状态初始化
从本地存储预判断登录状态,减少校验等待时间,避免初始状态完全为false:
修改后的store.js示例:
// @/vuex/store.js import { createStore } from 'vuex' export const store = createStore({ state: { // 初始时从本地存储读取token,初步判断登录状态 isLogin: !!localStorage.getItem('token'), token: localStorage.getItem('token') || '', user: null }, mutations: { SET_TOKEN(state, token) { state.token = token; localStorage.setItem('token', token); state.isLogin = true; }, SET_USER(state, user) { state.user = user; }, LOGOUT(state) { state.token = ''; state.user = null; state.isLogin = false; localStorage.removeItem('token'); } }, actions: { async fetchToken({ commit }, credentials) { // 替换为你的登录接口请求逻辑 const res = await fetch('/api/login', { method: 'POST', body: JSON.stringify(credentials) }); const data = await res.json(); commit('SET_TOKEN', data.token); }, async fetchUserLogin({ state, commit }) { if (!state.token) { commit('LOGOUT'); return; } // 替换为你的token校验/用户信息获取接口 try { const res = await fetch('/api/user', { headers: { Authorization: `Bearer ${state.token}` } }); if (res.ok) { const user = await res.json(); commit('SET_USER', user); } else { commit('LOGOUT'); } } catch (err) { commit('LOGOUT'); } } } })
关键要点总结
- 提前执行登录校验:把校验逻辑从
onMounted移到onBeforeMount或路由守卫中,避免页面先渲染错误内容 - 添加加载过渡:用加载态阻断未校验时的组件渲染,消除闪现
- 路由权限全覆盖:处理已登录/未登录用户的路由跳转逻辑,避免非法访问
- 状态预初始化:从本地存储预判断登录状态,缩短校验等待窗口
内容的提问来源于stack exchange,提问作者jemz
相关产品推荐
相关产品推荐

