You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3+Vue Router4导航守卫致Pinia中router.push报错undefined

解决Vue 3 + Pinia + Vue Router 4中router.push() undefined错误

问题描述

在Vue 3项目中使用Vue Router 4的导航守卫时,Pinia store里的router.push('/')和router.push({ name: "login" })均出现undefined错误,代码执行时抛出Cannot read properties of undefined (reading 'push')异常。相关代码及错误截图如下:

路由文件代码

import { createRouter, createWebHistory } from "vue-router";
import manageStaffRoutes from "./manage.staff.js";
import authRoutes from "./login.js";

import { useAuthStore } from "@/stores/auth.store.js";

const routes = [...manageStaffRoutes, ...authRoutes];

const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes,
});

router.beforeEach(async (to, from) => {
    const auth = await useAuthStore();
    const publicPages = ["/login", "/super-admin-login"];
    const authRequired = !publicPages.includes(to.path);
    if (authRequired && !auth.user) {
        return "/";
    }
});
export default router;

Pinia store代码

import { defineStore } from "pinia";
import { ref, computed } from "vue";
import axios from "axios";
import { useRouter } from "vue-router";

export const useAuthStore = defineStore("userAuth", () => {
    const router = useRouter();
    const userData = ref(null);
    const errorMessages = ref(null);

    const user = computed(() => {
        return JSON.parse(localStorage.getItem("user"));
    });

    if (user.value) {
        axios.defaults.headers.common["Authorization"] = `${user.value.token}`;
    }

    async function login(email, password) {
        try {
            const data = await axios.post("api/v1/users/login", {
                email: email,
                password: password,
            });
            if (data.status === 200) {
                userData.value = data.data;
                localStorage.setItem(
                    "user",
                    JSON.stringify(userData.value.data)
                );
                await router.push("/"); // 报错位置
               
            }
        } catch (error) {
            console.log(error);
            return (errorMessages.value = error.response.data.errorsToSend);
        }
    }

    const logout = async () => {
        try {
            const data = await axios.post("api/v1/users/logout");
            console.log(data);
            if (data.status === 201) {
                user.value = null;
                localStorage.removeItem("user");
                await router.push({ name: "login" }); // 报错位置
            }
        } catch (error) {
            console.log(error);
            // return (errorMessages.value = error.response.data.message);
        }
    };
    return { login, user, errorMessages, logout };
});

错误截图

错误截图

错误原因

  1. Pinia store中过早调用useRouter():useRouter()是Vue Router提供的组合式函数,需要在Vue的响应式上下文(如组件setup、钩子函数或Pinia action内部)中调用。而在store的顶层(defineStore回调的根级别)调用时,Vue Router实例尚未被注入到应用中,导致返回undefined。
  2. 路由守卫中错误使用useAuthStore:useAuthStore()是同步创建store实例的函数,不需要用await修饰;同时未授权时跳转到"/"会触发导航守卫循环重定向,逻辑错误。
  3. logout方法中错误修改computed属性:user是基于localStorage的computed属性,直接赋值user.value = null无效,因为computed是只读的。

解决方案

1. 修正Pinia store中router的获取方式

将useRouter()移到login和logout方法内部,确保在Vue上下文环境中调用:

import { defineStore } from "pinia";
import { ref, computed } from "vue";
import axios from "axios";
import { useRouter } from "vue-router";

export const useAuthStore = defineStore("userAuth", () => {
    const userData = ref(null);
    const errorMessages = ref(null);

    const user = computed(() => {
        return JSON.parse(localStorage.getItem("user"));
    });

    if (user.value) {
        axios.defaults.headers.common["Authorization"] = `${user.value.token}`;
    }

    async function login(email, password) {
        const router = useRouter(); // 移到方法内部
        try {
            const data = await axios.post("api/v1/users/login", {
                email: email,
                password: password,
            });
            if (data.status === 200) {
                userData.value = data.data;
                localStorage.setItem(
                    "user",
                    JSON.stringify(userData.value.data)
                );
                // 更新请求头
                axios.defaults.headers.common["Authorization"] = `${userData.value.data.token}`;
                await router.push("/");
            }
        } catch (error) {
            console.log(error);
            errorMessages.value = error.response?.data?.errorsToSend || '登录失败';
        }
    }

    const logout = async () => {
        const router = useRouter(); // 移到方法内部
        try {
            const data = await axios.post("api/v1/users/logout");
            console.log(data);
            if (data.status === 201) {
                localStorage.removeItem("user");
                delete axios.defaults.headers.common["Authorization"];
                await router.push({ name: "login" });
            }
        } catch (error) {
            console.log(error);
        }
    };
    return { login, user, errorMessages, logout };
});

2. 修正路由守卫逻辑

移除useAuthStore前的await,修改未授权时的跳转目标为登录页,避免循环重定向:

import { createRouter, createWebHistory } from "vue-router";
import manageStaffRoutes from "./manage.staff.js";
import authRoutes from "./login.js";

import { useAuthStore } from "@/stores/auth.store.js";

const routes = [...manageStaffRoutes, ...authRoutes];

const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes,
});

router.beforeEach((to, from) => {
    const auth = useAuthStore(); // 移除await
    const publicPages = ["/login", "/super-admin-login"];
    const authRequired = !publicPages.includes(to.path);
    if (authRequired && !auth.user) {
        return "/login"; // 跳转到登录页而非主页
    }
});
export default router;

关键修改点说明

  • router实例获取时机:在action内部调用useRouter(),确保处于Vue响应式上下文,能正确获取路由实例。
  • 导航守卫逻辑:同步获取store实例,修正跳转目标避免循环重定向。
  • computed属性操作:通过修改localStorage来更新user的computed值,而非直接赋值computed属性;同时清理axios请求头,避免无效授权。

内容的提问来源于stack exchange,提问作者Franz Schad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 06:00:59