Vue3登录状态存储求助:路由切换后状态丢失
问题解决:Vue3登录后导航栏状态路由切换丢失
你的核心问题是登录状态仅存于Login组件的局部data中,路由切换时Login组件销毁,状态随之丢失;同时你虽使用了Vuex,但未将登录状态维护在全局store里,反而用组件传参的方式,导致状态无法跨路由持久化。以下是具体修正方案:
步骤1:用Vuex全局维护登录状态
先完善Vuex的auth模块,专门处理登录状态:
// store/modules/auth.js export default { namespaced: true, state: { isLoggedIn: false }, mutations: { SET_LOGIN_STATUS(state, status) { state.isLoggedIn = status; } }, actions: { // 登录接口调用 async login({ commit }, credentials) { const response = await this.$axios.post('/api/login', credentials); const data = response.data; if (data.success) { commit('SET_LOGIN_STATUS', true); // 存token到localStorage,实现刷新页面保持登录 localStorage.setItem('token', data.token); } return data; }, // 登出 logout({ commit }) { commit('SET_LOGIN_STATUS', false); localStorage.removeItem('token'); }, // 页面刷新时恢复登录状态 checkLogin({ commit }) { const token = localStorage.getItem('token'); if (token) { // 可额外验证token有效性,这里做简单处理 commit('SET_LOGIN_STATUS', true); } } }, getters: { isLoggedIn: state => state.isLoggedIn } };
在store主文件注册模块:
// store/index.js import { createStore } from 'vuex'; import auth from './modules/auth'; export default createStore({ modules: { auth } });
步骤2:修正Navbar组件,直接读取全局状态
删除冗余的props和局部data,直接从Vuex获取状态:
<template> <nav class="navbar-light bg-light"> <ul class="ul1"> <li><router-link to="/"> <button class="btn inscription-button"> Accueil </button> </router-link></li> <li><router-link to="/informations" class="btn inscription-button"> Informations </router-link></li> <li><router-link to="/tasklist" class="btn inscription-button"> Liste de tâches </router-link></li> <!-- 直接用Vuex全局状态控制显示 --> <router-link to="/createtask" v-if="isLoggedIn" class="btn inscription-button"> Créer une tâche </router-link> <li><router-link to="/contact" class="btn inscription-button"> Contact </router-link></li> </ul> <ul> <li v-if="!isLoggedIn"> <router-link to="/login">Login</router-link> </li> <li v-if="isLoggedIn"> <button @click="logout">Logout</button> </li> </ul> </nav> </template> <script> import { mapActions, mapGetters } from 'vuex'; export default { name: 'Navbar', computed: { // 从Vuex获取全局登录状态 ...mapGetters('auth', ['isLoggedIn']) }, methods: { // 调用Vuex的登出action ...mapActions('auth', ['logout']), }, // 页面加载时检查登录状态,刷新页面也能保留 mounted() { this.$store.dispatch('auth/checkLogin'); } }; </script>
步骤3:修正Login组件,移除局部状态和重复Navbar
Login组件无需单独引入Navbar(App.vue已全局挂载),登录成功后更新Vuex状态:
<template> <!-- 移除重复的Navbar组件 --> <section class="vh-100"> <div class="container py-5 h-100"> <div class="row d-flex align-items-center justify-content-center h-100"> <div class="col-md-8 col-lg-7 col-xl-6"> <img src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-login-form/draw2.svg" class="img-fluid" alt="Phone image"> </div> <div class="col-md-7 col-lg-5 col-xl-5 offset-xl-1"> <form @submit.prevent="submitForm"> <div class="form-outline mb-4"> <input type="email" id="form1Example13" class="form-control form-control-lg" required v-model="email" name="user_mail" /> <label class="form-label" for="form1Example13">Adresse email</label> </div> <div class="form-outline mb-4"> <input type="password" id="form1Example23" class="form-control form-control-lg" required v-model="password" name="user_password" /> <label class="form-label" for="form1Example23">Mot de passe</label> </div> <div class="d-flex justify-content-around align-items-center mb-4"> <div class="form-check"> <input class="form-check-input" type="checkbox" value="" id="form1Example3" checked /> <label class="form-check-label" for="form1Example3"> Se souvenir de moi </label> </div> <a href="#!">Mot de passe oublié ?</a> </div> <button type="submit" class="btn btn-primary btn-lg btn-block">Se connecter</button> <div class="divider d-flex align-items-center my-4"></div> </form> </div> </div> </div> </section> </template> <script> import { mapActions } from "vuex"; import Swal from 'sweetalert2' export default { data() { return { email: '', password: '' // 移除局部的isLoggedIn状态 } }, methods: { submitForm: async function () { const response = await this.login({ email: this.email, password: this.password }); if(response.success) { Swal.fire({ title: 'Connexion réussie ! ', text: response.message, icon: 'success' }); this.$router.push('/tasklist') } else { Swal.fire({ title: 'Connexion échouée ', text: response.message, icon: 'error' }); } }, // 调用Vuex的登录action ...mapActions("auth", ["login"]), } } </script>
步骤4:App.vue全局挂载Navbar
确保整个应用只有一个Navbar实例,所有路由页面共用:
<template> <Navbar /> <router-view /> </template> <script> import Navbar from './components/Navbar.vue'; export default { components: { Navbar } } </script>
为什么之前的方法失效?
- 局部状态丢失:登录状态存在Login组件的data中,路由切换后组件销毁,状态随之消失;
- 多Navbar实例:每个页面单独引入Navbar会创建多个独立实例,状态无法共享;
- 状态维护混乱:同时使用props、局部data和Vuex,导致状态同步逻辑冲突。
现在通过Vuex全局维护状态,配合全局Navbar实例,就能保证路由切换时状态持久化。
内容的提问来源于stack exchange,提问作者Fouzi benzidane
相关产品推荐
相关产品推荐

