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

Nuxt.js中Snackbar状态不更新问题排查

Vue迁移Nuxt.js后Snackbar无法显示的问题

迁移项目到Nuxt.js后,遇到以下问题:在路由中间件中调用Pinia store的showSnackbar方法后,使用navigateTo跳转页面时Snackbar完全不显示;但改用router.push跳转时,Snackbar能正常展示。

相关代码

Snackbar组件

<template>
  <v-snackbar v-model="snackbar" :timeout="timeout" :color="color">
    {{ message }}
  </v-snackbar>
</template>

<script setup>
import { ref, watch } from 'vue';
import { useUserStore } from '~/store/user';

const store = useUserStore()

const snackbar = ref(false);
const message = ref('');
const timeout = ref(3000);
const color = ref('error');

console.log("STORE SNACKBAR", store.snackbarVisible)
console.log("STORE SNACKBAR mesage", store.snackbarMessage)

// 监听Pinia store状态变化
watch(
  () => store.snackbarVisible,
  (newVal) => {
    console.log("newval", newVal)
    console.log(store.snackbarVisible)
    snackbar.value = newVal;
    console.log("IN SNACLBAR", snackbar)
    if (newVal) {
      message.value = store.snackbarMessage;
      console.log("IN SNACKMAR MEESATE", message.value)
    }
  }
);
</script>

Pinia Store

import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    auth: false,
    admin: false,
    snackbarMessage: '',
    snackbarVisible: false
  }),
  getters: {
    isAuthenticated: state => state.auth === true,
    isAdmin: state => state.admin === true,
    isSnackBarVisible: state => state.snackbarVisible === true
  },
  actions: {
    initializeAuth() {
      this.auth = useCookie('userLoggedIn').value === 1;
      this.admin = useCookie('admin').value === 1;
    },
    setUser(user) {
      this.auth = user.auth;
      this.admin = user.admin;
    },
    showSnackbar(message) {
      this.snackbarMessage = message;
      this.snackbarVisible = true;
      console.log("AICI IN STORE")
      console.log("SNACKBAR VISSBILE", this.snackbarVisible)
      setTimeout(() => {
        this.snackbarMessage = '';
        this.snackbarVisible = false;
        console.log("SNACKBAR TERMINATED")
      }, 4000);
    }
  }
});

路由中间件(middleware/auth.js)

import { useUserStore } from "~/store/user";

export default defineNuxtRouteMiddleware(async (to, from) => {
  const userStore = useUserStore()
  const isUserloggedInCookie = useCookie('userLoggedIn')
  const isAdminloggedInCookie = useCookie('admin')
 
  const user = {
    auth: isUserloggedInCookie.value === 1,
    admin: isAdminloggedInCookie.value === 1
  }
  userStore.setUser(user)
 
  const isAuth = userStore.isAuthenticated;

  if (!isAuth) {
    userStore.showSnackbar('You need to be logged in!');
    return navigateTo('/user/logout');
  }
});

控制台日志

// showSnackBar被调用时
AICI IN STORE
SNACKBAR VISSBILE  true
// SnackBar组件初始化时
STORE SNACKBAR false
STORE SNACKBAR mesage 
// setTimeout执行后
SNACKBAR TERMINATED

问题原因

  1. 路由中间件执行时机早于页面组件挂载:中间件在页面组件渲染前执行,此时页面内的Snackbar组件还未创建,watch监听器尚未注册,无法捕获store的状态变化。
  2. navigateTo的即时跳转特性:navigateTo会立即触发页面跳转,当前页面组件来不及完成渲染和状态监听就被销毁。
  3. router.push的异步特性:router.push是客户端路由跳转,会等待当前事件循环任务完成后再执行跳转,此时页面组件已挂载,监听器生效,能正常显示Snackbar。

解决方案

方案1:全局挂载Snackbar组件

将Snackbar组件放在app.vue中,确保它在应用生命周期内始终存在,不受页面跳转影响:

<!-- app.vue -->
<template>
  <NuxtPage />
  <Snackbar />
</template>

<script setup>
import Snackbar from '~/components/Snackbar.vue'
</script>

方案2:延迟导航跳转

在调用showSnackbar后延迟执行navigateTo,给Snackbar足够的渲染时间:

// middleware/auth.js
import { useUserStore } from "~/store/user";

export default defineNuxtRouteMiddleware(async (to, from) => {
  // ... 原有代码 ...

  if (!isAuth) {
    userStore.showSnackbar('You need to be logged in!');
    // 延迟100ms跳转,保证Snackbar完成渲染
    setTimeout(() => {
      navigateTo('/user/logout');
    }, 100);
  }
});

方案3:客户端环境下使用router.push

如果中间件仅在客户端执行,直接使用router.push替代navigateTo:

// middleware/auth.js
import { useUserStore } from "~/store/user";
import { useRouter } from 'vue-router';

export default defineNuxtRouteMiddleware(async (to, from) => {
  const router = useRouter();
  // ... 原有代码 ...

  if (!isAuth) {
    userStore.showSnackbar('You need to be logged in!');
    if (process.client) {
      router.push('/user/logout');
    } else {
      // 服务端环境仍使用navigateTo
      return navigateTo('/user/logout');
    }
  }
});

内容的提问来源于stack exchange,提问作者Misu Stefan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:40:56