Vue 3.0与Vue Router 4.0技术问题:如何在导航守卫中访问插件并修复next()回调失效问题
Hey there, let's fix your Vue Router issues one by one—first, the big misunderstanding with next() callbacks, then how to access your plugin data in navigation guards.
First: Why Your next(vm => ...) Callback Isn't Working
You're hitting a common misconception about Vue Router 4's next() function: passing a function to next() doesn't control whether navigation is allowed. Instead, that function runs after the navigation has already completed and the target component is mounted to the DOM.
That's why your console.log(vm) never fires—when the beforeEach guard runs, the component instance (vm) doesn't exist yet. And returning vm.$myPluginData.canNavigate from that callback does nothing to block or allow navigation, since the decision was already made before the callback runs.
To control navigation, you need to call next() with a boolean (true/false), a route location, or omit the argument entirely (which is equivalent to next(true)).
Second: Accessing Your Plugin Data in Navigation Guards
Since beforeEach runs before the target component is created, you can't rely on vm to get your plugin's $myPluginData. Instead, you can directly import the reactive data from your plugin, since it's a shared reactive object.
Here's how to adjust your code:
Step 1: Export the Reactive Data from Your Plugin
Update your plugin file to export the reactiveData object so you can access it elsewhere:
import { reactive, readonly } from 'vue' // Export this so we can use it in the router guard export const reactiveData = reactive({ canNavigate: false }) export default { install: app => { app.config.globalProperties.$myPluginData = reactiveData app.provide('MyPlugin', readonly(reactiveData)) } }
Step 2: Use the Exported Data in Your Navigation Guard
Import the reactiveData into your router file and use it directly to decide navigation:
import { createRouter, createWebHashHistory } from 'vue-router' import { reactiveData } from './path-to-your-plugin-file' // Replace with your actual plugin path import Main from '../components/pages/Main.vue' export const ROUTES = [ { path: '/', name: 'main', component: Main, meta: { shouldCheck: false } }, { path: '/protected-route', name: 'protected-route', component: () => import('../components/pages/ProtectedComponent.vue'), meta: { shouldCheck: true } } ] const router = createRouter({ history: createWebHashHistory(), routes: ROUTES }) router.beforeEach((to, from, next) => { if (!to.meta.shouldCheck) { return next() } // Check the plugin's reactive data directly if (reactiveData.canNavigate) { next() // Allow navigation to the protected route } else { next(false) // Block navigation (or redirect with next('/') if preferred) } }) createApp(App) .use(MyPlugin) .use(router) .mount('#app')
Why This Works
reactiveDatais a shared reactive object, so any changes tocanNavigatewill be reflected immediately in the navigation guard.- You don't need to wait for a component instance to exist—you're accessing the data directly from the source, which is available as soon as your app loads.
If you prefer not to export the reactive data (e.g., for encapsulation), another option is to attach it to the router instance when installing the plugin, but exporting is the simplest and most straightforward solution here.
内容的提问来源于stack exchange,提问作者dragonmnl

