Vue Router 4【实用教程】(2024最新版)vue3 路由管理

Vue Router 是 Vue 官方的客户端路由解决方案,在单页应用 (SPA) 中,用户在应用中浏览不同页面时,URL 会随之更新,但页面不需要从服务器重新加载。

核心思想:

通过配置路由来告诉 Vue Router 为每个 URL 路径显示哪些组件。

官网

https://router.vuejs.org/zh/guide/

安装

通常创建 vue3 项目时,选择安装 Pinia 就会自动集成。

但若目前项目里没有,则按如下流程操作

npm install vue-router@4

新建文件 src/views/Index.vue

<template><div>首页</div>
</template>

新建文件 src/router/index.ts

import { createRouter, createWebHistory } from "vue-router";
import Index from "../views/Index.vue";const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: "/",component: Index,},],
});export default router;

修改 src/App.vue 为

<template><RouterView />
</template>

在 src/main.ts 中导入注册 Vue Router

import router from './router'
app.use(router)

内置组件

RouterLink

用于替代 <a> 标签,创建页面跳转的链接,实现在不重新加载页面的情况下改变 URL。

<RouterLink to="/">首页</RouterLink>
  • to 属性的值为 Vue Router 路由配置中的目标 URL(类似<a> 标签的 href 属性 )

  • to 属性的值可以是对象,语法和下文中的 push 相同(本质即自动调用 router.push 来触发导航)

  • replace 属性实现下文中 replace 的效果

    <router-link :to="..." replace>
    
  • RouterLink 的 v-slot 中可以访问与下文 useLink 组合式函数相同的属性

自定义 RouterLink

例如导航菜单中的链接,处理外部链接,添加 inactive-class 等

<script setup>
import { computed } from 'vue'
import { RouterLink } from 'vue-router'defineOptions({inheritAttrs: false,
})const props = defineProps({// 如果使用 TypeScript,请添加 @ts-ignore...RouterLink.props,inactiveClass: String,
})const isExternalLink = computed(() => {return typeof props.to === 'string' && props.to.startsWith('http')
})
</script><template><a v-if="isExternalLink" v-bind="$attrs" :href="to" target="_blank"><slot /></a><router-linkv-elsev-bind="$props"customv-slot="{ isActive, href, navigate }"><av-bind="$attrs":href="href"@click="navigate":class="isActive ? activeClass : inactiveClass"><slot /></a></router-link>
</template>

RouterView

用于渲染当前 URL 路径对应的路由组件,可以放在任何地方,不一定要在 App.vue 中。

  <main><RouterView /></main>

命名视图

  • name 属性可对视图进行命名(默认值为 default),用于在一个页面,渲染多个组件。
<router-view class="view left-sidebar" name="LeftSidebar" />
<router-view class="view main-content" />
<router-view class="view right-sidebar" name="RightSidebar" />

路由配置时,需配置多个组件,使用 components 属性,值为对象(属性为视图名称,属性值为组件)

    {path: '/',components: {default: Home,// LeftSidebar: LeftSidebar 的缩写LeftSidebar,// 它们与 `<router-view>` 上的 `name` 属性匹配RightSidebar,},},

也可在嵌套路由中使用

{path: '/settings',// 你也可以在顶级路由就配置命名视图component: UserSettings,children: [{path: 'emails',component: UserEmailsSubscriptions}, {path: 'profile',components: {default: UserProfile,helper: UserProfilePreview}}]
}

插槽

<router-view v-slot="{ Component }"><component :is="Component" />
</router-view>

等价于不带插槽的 <router-view />

用途1:添加组件缓存和路由切换的过渡

<router-view v-slot="{ Component }"><transition><keep-alive><component :is="Component" /></keep-alive></transition>
</router-view>

用途2:添加模板引用

<router-view v-slot="{ Component }"><component :is="Component" ref="mainContent" />
</router-view>

避免将引用放在 <router-view> 上,被 RouterView 的实例填充

用途3:插槽传参【不推荐】

<RouterView v-slot="{ Component }"><component:is="Component"view-prop="value"/>
</RouterView>

所有视图组件都会接收到 view-prop,即所有的视图组件都声明了一个 view-prop 的 prop,但这未必需要。

路由懒加载

即当路由被访问时才加载对应组件,可以提升性能。

以下写法为静态导入组件

src/router/index.ts 中

import Index from "../views/Index.vue";
    {path: "/",component: Index,},

需改为动态导入

采用箭头函数的写法,返回 import() 函数

    {path: "/",component: () => import("../views/Index.vue"),},

建议:所有的路由都使用动态导入

配置路由

可通过下方链接,测试路由匹配规则
https://paths.esm.dev/

默认匹配模式

  • 不区分大小写
  • 匹配带有或不带有尾部斜线的路由

/users 将匹配 /users、/users/、甚至 /Users/

路由模式 history

【推荐】HTML5 模式

import { createRouter, createWebHistory } from 'vue-router'const router = createRouter({history: createWebHistory(),routes: [//...],
})

Hash 模式

会在实际 URL 之前添加哈希字符 #

import { createRouter, createWebHashHistory } from 'vue-router'const router = createRouter({history: createWebHashHistory(),routes: [//...],
})

Memory 模式

用于Node 环境和 SSR,不会有历史记录(无法后退或前进)。

import { createRouter, createMemoryHistory } from 'vue-router'
const router = createRouter({history: createMemoryHistory(),routes: [//...],
})

路由选项 strict sensitive

在 src/router/index.ts 中添加选项

// 严格模式:不匹配带有尾部斜线的路由
strict: true, 
// 区分大小写
sensitive: true,

静态路由

像首页这种,路径和组件一一对应的关系为静态路由

    {path: "/",component: () => import("../views/Index.vue"),},

动态路由 :

若不同路径,对应的同一个组件,则是动态路由

使用场景

路径参数不同,但渲染同一个组件

实战范例

访问路由 ‘/user/1’ 和 ‘/user/2’ ,都渲染 User 组件,其中的路径参数 12 为用户 ID

    {path: "/users/:id",component: () => import("../views/User.vue"),},

一个路由中可设置多个路径参数

path: "/users/:username/posts/:postId",

页面模板中,可通过 $route.params 获取到路径参数,效果如下

匹配模式匹配路径route.params
/users/:username/users/eduardo{ username: 'eduardo' }
/users/:username/posts/:postId/users/eduardo/posts/123{ username: 'eduardo', postId: '123' }

动态路由切换时,会复用相同的组件实例(提升性能),所以组件的生命周期钩子不会被调用,此时要想对路径参数的变化做出响应,需使用 watch

<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'const route = useRoute()watch(() => route.params.id, (newId, oldId) => {// 对路由变化做出响应...
})
</script>

或 路由守卫 beforeRouteUpdate

<script setup>
import { onBeforeRouteUpdate } from 'vue-router'onBeforeRouteUpdate(async (to, from) => {// 对路由变化做出响应...userData.value = await fetchUser(to.params.id)
})
</script>

自定义正则的路径参数

可选的路径参数,添加 ?

  // 匹配 /users 和 /users/posva{ path: '/users/:userId?' },

限数字的路径参数,用 (\\d+)

// orderId 只能为数字
{ path: '/:orderId(\\d+)' },

可重复的参数,用 *(0 个或多个)和 +(1 个或多个)

  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等{ path: '/:chapters+' },// /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等{ path: '/:chapters*' },

结合使用 – 可重复的数字参数

  // 匹配 /1, /1/2, 等{ path: '/:chapters(\\d+)+' },

命名路由 name

可以给路由取个名字,但所有路由的命名都必须是唯一的(路由重名时,只会保留最后一条)

  {path: '/user/:username',name: 'profile', component: User}

可用于路由跳转

<router-link :to="{ name: 'profile', params: { username: 'erina' } }">User profile
</router-link>

使用 name 还有以下优点:

  • 没有硬编码的 URL。
  • params 的自动编码/解码。
  • 防止你在 URL 中出现打字错误。
  • 绕过路径排序,例如展示一个匹配相同路径但排序较低的路由。

嵌套路由 children

页面中的局部区域需要随路由改变时,则需要嵌套路由

实战范例

/user/:id/info 路由显示用户的信息
/user/:id/works 路由显示用户的作品

首先,需将 User 组件局部改变的区域替换为 <router-view />

<!-- User.vue -->
<template><div class="user"><h2>User {{ $route.params.id }}</h2><!-- 局部改变的区域 --><router-view /></div>
</template>

嵌套路由的配置如下:

  {path: '/user/:id',component: User,children: [// 当 /user/:id 匹配成功// UserHome 将被渲染到 User 的 <router-view> 内部{ path: '', component: UserHome },{// 当 /user/:id/info 匹配成功// UserInfo 将被渲染到 User 的 <router-view> 内部path: 'info',component: UserInfo,},{// 当 /user/:id/works 匹配成功// UserWorks将被渲染到 User 的 <router-view> 内部path: 'works',component: UserWorks,},

组件,其中的路径参数 12 为用户 ID

路由重定向 redirect

指当用户访问 /home 时,URL 会被 / 替换,然后匹配成 /

// 重定向至 -- 目标路径
[{ path: '/home', redirect: '/' }]// 重定向至 -- 命名路由
[{ path: '/home', redirect: { name: 'homepage' } }]// 属性值可以是方法,以便获取路由参数
{// /search/screens -> /search?q=screenspath: '/search/:searchText',redirect: to => {// 方法接收目标路由作为参数// return 重定向的字符串路径/路径对象return { path: '/search', query: { q: to.params.searchText } }},
},// 相对重定向
{// 将总是把/users/123/posts重定向到/users/123/profile。path: '/users/:id/posts',redirect: to => {// 该函数接收目标路由作为参数// 相对位置不以`/`开头// 或 { path: 'profile'}return 'profile'},
},

路由别名 alias

将 / 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。

{ path: '/', component: Homepage, alias: '/home' }

alias 的值可为数组

  {path: '/users',component: UsersLayout,children: [// 为这 3 个 URL 呈现 UserList// - /users// - /users/list// - /people{ path: '', component: UserList, alias: ['/people', 'list'] },],},

若路由有参数,在任何绝对别名中需包含它们:

  {path: '/users/:id',component: UsersByIdLayout,children: [// 为这 3 个 URL 呈现 UserDetails// - /users/24// - /users/24/profile// - /24{ path: 'profile', component: UserDetails, alias: ['/:id', ''] },],},

路由元信息 meta

在路由上添加更多信息,如过渡名称、访问权限等

  {path: '/posts',component: PostsLayout,children: [{path: 'new',component: PostsNew,// 只有经过身份验证的用户才能创建帖子meta: { requiresAuth: true },},{path: ':id',component: PostsDetail// 任何人都可以阅读文章meta: { requiresAuth: false },}]}

在路由守卫(详见下文)中使用

router.beforeEach((to, from) => {// 而不是去检查每条路由记录// to.matched.some(record => record.meta.requiresAuth)if (to.meta.requiresAuth && !auth.isLoggedIn()) {// 此路由需要授权,请检查是否已登录// 如果没有,则重定向到登录页面return {path: '/login',// 保存我们所在的位置,以便以后再来query: { redirect: to.fullPath },}}
})

404 路由

写在路由配置的末尾,用于匹配所有路由,展示路由匹配失败的 404 页面。

{ path: '/:pathMatch(.*)*', name: '404', component: () => import("../views/404.vue"), },

路径参数变组件传参 prop

即通过 defineProps 获取路径参数,提升了组件的通用性

<!-- User.vue -->
<script setup>
defineProps({id: String
})
</script><template><div>User {{ id }}</div>
</template>

路由配置需添加 props 选项

{ path: '/user/:id', component: User, props: true }

命名视图的路由,需为每个命名视图定义 props 配置

  {path: '/user/:id',components: { default: User, sidebar: Sidebar },props: { default: true, sidebar: false }}

props 的值可以是函数(需为无状态的)

//  “/search?q=vue” 将传递 {query: 'vue'} 作为 props 传给 SearchUser 组件。{path: '/search',component: SearchUser,props: route => ({ query: route.query.q })}

路由器对象 $router

模板中为 $router

JS 中为

import { useRouter} from 'vue-router'const router = useRouter()
  • 检查路由是否存在 router.hasRoute()
  • 获取所有路由记录的数组 router.getRoutes()

添加路由

在项目运行过程中,添加未注册的路由

router.addRoute({ path: '/about',name:'about', component: About })

为避免名字冲突,可以在路由中使用 Symbol 作为名字。

添加嵌套路由

router.addRoute({name: 'admin',path: '/admin',component: Admin,children: [{ path: 'settings', component: AdminSettings }],
})

router.addRoute({name: 'admin',path: '/admin',component: Admin,children: [{ path: 'settings', component: AdminSettings }],
})

删除路由

在项目运行过程中,删除已注册的路由,所有的别名和子路由也会被同时删除

方法1 添加重名路由

如果添加与现有途径名称相同的途径,会先删除路由,再添加路由。

router.addRoute({ path: '/about', name: 'about', component: About })
// 这将会删除之前已经添加的路由,因为他们具有相同的名字且名字必须是唯一的
router.addRoute({ path: '/other', name: 'about', component: Other })

方法2 调用添加路由的回调

适合没有名称的路由

const removeRoute = router.addRoute(routeRecord)
removeRoute() // 删除路由如果存在的话

方法3 removeRoute

router.removeRoute(‘home’)
  • 参数为路由的名称

当前路由对象 $route

模板中为 $route

JS 中为

import { useRoute } from 'vue-router'const route = useRoute()

获取当前路由中的参数

route.params

useLink

Vue Router 暴露的路由信息,可用于构建自己的 RouterLink 组件或生成自定义链接,详细用法如下:

<script setup>
import { RouterLink, useLink } from 'vue-router'
import { computed } from 'vue'const props = defineProps({// 如果使用 TypeScript,请添加 @ts-ignore...RouterLink.props,inactiveClass: String,
}const {// 解析出来的路由对象route,// 用在链接里的 hrefhref,// 布尔类型的 ref 标识链接是否匹配当前路由isActive,// 布尔类型的 ref 标识链接是否严格匹配当前路由isExactActive,// 导航至该链接的函数navigate
} = useLink(props)const isExternalLink = computed(() => typeof props.to === 'string' && props.to.startsWith('http')
)
</script>

路由跳转

  • 模板中跳转路由,通过内置组件 RouterLink
  • JS 中跳转路由,通过路由器实例的各种 API

导航是异步的,返回一个 Promise!

首先获取路由器实例

import { useRouter} from 'vue-router'const router = useRouter()

push 新增跳转

  • 会向 history 栈添加一个新的记录,当用户点击浏览器后退按钮时,会回到之前的 URL。( 效果同 window.history.pushState )
  • RouterLink 中 to 属性语法与 push 相同
  • params 不能与 path 一起使用
  • 任何类型的 params 都会转为字符串
// 字符串路径
router.push('/users/eduardo')// 带有路径的对象
router.push({ path: '/users/eduardo' })// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })
const username = 'eduardo'
// 我们可以手动建立 url,但我们必须自己处理编码
router.push(`/user/${username}`) // -> /user/eduardo
// 同样
router.push({ path: `/user/${username}` }) // -> /user/eduardo
// 如果可能的话,使用 `name` 和 `params` 从自动 URL 编码中获益
router.push({ name: 'user', params: { username } }) // -> /user/eduardo

replace 替代跳转

  • 不会向 history 添加新记录( 效果同 window.history.replaceState ),其他与 push 相同
  • push 添加 replace 参数,效果与 replace 相同
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })

go 越级跳转

参数为整数,用于在历史堆栈中前进或后退多少步( 效果同 window.history.go)

// 向前移动一条记录,与 router.forward() 相同
router.go(1)// 返回一条记录,与 router.back() 相同
router.go(-1)// 前进 3 条记录
router.go(3)// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)

路由守卫

即在路由跳转/取消时自定义逻辑。

全局前置守卫 beforeEach

导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。

src/router/index.ts 中

const router = createRouter({ ... })router.beforeEach((to, from) => {// ...// 返回 false 以取消导航return false
})

参数

  • to —— 即将要进入的目标
  • from —— 当前导航正要离开的路由

返回值

  • false —— 取消当前的导航。
  • 一个路由地址 —— 重定向到一个不同的地址
  • undefined / true —— 执行导航/调用下一个导航守卫
 router.beforeEach(async (to, from) => {if (// 检查用户是否已登录!isAuthenticated &&// ❗️ 避免无限重定向to.name !== 'Login') {// 将用户重定向到登录页面return { name: 'Login' }}})

全局解析守卫 beforeResolve

在导航被确认之前、所有组件内守卫和异步路由组件被解析之后调用。

router.beforeResolve(async to => {if (to.meta.requiresCamera) {try {await askForCameraPermission()} catch (error) {if (error instanceof NotAllowedError) {// ... 处理错误,然后取消导航return false} else {// 意料之外的错误,取消导航并把错误传给全局处理器throw error}}}
})

全局后置钩子 afterEach

用于分析、更改页面标题、声明页面等辅助功能

router.afterEach((to, from) => {sendToAnalytics(to.fullPath)
})

第三个参数为导航结果,值为 true/false

router.afterEach((to, from, failure) => {if (!failure) sendToAnalytics(to.fullPath)
})

路由守卫内的全局注入

vue3.3

在 app.provide() 中提供的所有内容都可以在 router.beforeEach()、router.beforeResolve()、router.afterEach() 内获取到

// main.ts
const app = createApp(App)
app.provide('global', 'hello injections')// router.ts or main.ts
router.beforeEach((to, from) => {const global = inject('global') // 'hello injections'// a pinia storeconst userStore = useAuthStore()// ...
})

路由配置中定义路由独享守卫

  {path: '/users/:id',component: UserDetails,beforeEnter: (to, from) => {// reject the navigationreturn false},},

beforeEnter 守卫只在进入路由时触发,不会在 params、query 或 hash 改变时触发。

beforeEnter 属性值可以是一个函数数组,便于不同的路由重用守卫

function removeQueryParams(to) {if (Object.keys(to.query).length)return { path: to.path, query: {}, hash: to.hash }
}function removeHash(to) {if (to.hash) return { path: to.path, query: to.query, hash: '' }
}const routes = [{path: '/users/:id',component: UserDetails,beforeEnter: [removeQueryParams, removeHash],},{path: '/about',component: UserDetails,beforeEnter: [removeQueryParams],},
]

组件中定义路由独享守卫

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import { ref } from 'vue'// 路由发生变化时触发(仅动态路由参数变化,不会触发)
onBeforeRouteLeave((to, from) => {const answer = window.confirm('Do you really want to leave? you have unsaved changes!')// 取消导航并停留在同一页面上if (!answer) return false
})const userData = ref()// 路由参数变化时触发
onBeforeRouteUpdate(async (to, from) => {//仅当 id 更改时才获取用户,例如仅 query 或 hash 值已更改if (to.params.id !== from.params.id) {userData.value = await fetchUser(to.params.id)}
})
</script>

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫(2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

路由过渡 transition

全局过渡

所有路由切换都添加过渡效果

<router-view v-slot="{ Component }"><transition name="fade"><component :is="Component" /></transition>
</router-view>

根据路由元信息添加过渡

  {path: '/custom-transition',component: PanelLeft,meta: { transition: 'slide-left' },},{path: '/other-transition',component: PanelRight,meta: { transition: 'slide-right' },},
<router-view v-slot="{ Component, route }"><!-- 使用任何自定义过渡和回退到 `fade` --><transition :name="route.meta.transition || 'fade'"><component :is="Component" /></transition>
</router-view>

根据路由添加过渡

<!-- 使用动态过渡名称 -->
<router-view v-slot="{ Component, route }"><transition :name="route.meta.transition"><component :is="Component" /></transition>
</router-view>

根据路径的深度动态添加信息到 meta 字段

router.afterEach((to, from) => {const toDepth = to.path.split('/').lengthconst fromDepth = from.path.split('/').lengthto.meta.transition = toDepth < fromDepth ? 'slide-right' : 'slide-left'
})

强制过渡 key

Vue 可能会自动复用看起来相似的组件,从而忽略了任何过渡,可通过 key 强制过渡

<router-view v-slot="{ Component, route }"><transition name="fade"><component :is="Component" :key="route.path" /></transition>
</router-view>

路由滚动 scrollBehavior

用于自定义路由切换时页面如何滚动

  • 只在支持 history.pushState 的浏览器中可用
const router = createRouter({history: createWebHashHistory(),routes: [...],scrollBehavior (to, from, savedPosition) {// return 期望滚动到哪个的位置}
})

scrollBehavior 函数

  • 参数 to —— 新路由
  • 参数 from —— 原路由
  • 参数 savedPosition —— 仅 popstate 导航时才可用(由浏览器的后退/前进按钮触发)
  • 返回值 —— ScrollToOptions 位置对象,若返回 falsy 值,或者空对象,则不滚动。
  scrollBehavior(to, from, savedPosition) {// 始终滚动到顶部return { top: 0 }},

相对目标元素偏移

  scrollBehavior(to, from, savedPosition) {// 始终在元素 #main 上方滚动 10pxreturn {// 也可以这么写// el: document.getElementById('main'),el: '#main',// 在元素上 10 像素top: 10,}},

若返回 savedPosition,则按下 后退/前进 按钮时,就会像浏览器的原生表现那样

  scrollBehavior(to, from, savedPosition) {if (savedPosition) {return savedPosition} else {return { top: 0 }}},

滚动到锚点 to.hash

  scrollBehavior(to, from, savedPosition) {if (to.hash) {return {el: to.hash,}}},

流畅滚动 smooth

  scrollBehavior(to, from, savedPosition) {if (to.hash) {return {el: to.hash,behavior: 'smooth',}}}

延迟滚动

通过返回一个 Promise实现,比如希望等待过渡结束后再滚动

const router = createRouter({scrollBehavior(to, from, savedPosition) {return new Promise((resolve, reject) => {setTimeout(() => {resolve({ left: 0, top: 0 })}, 500)})},
})

路由检测

以下情况会路由故障(留在原页面上):

  • 用户已经位于他们正在尝试导航到的页面
  • 一个导航守卫通过调用 return false 中断了这次导航
  • 当前的导航守卫还没有完成时,一个新的导航守卫会出现了
  • 一个导航守卫通过返回一个新的位置,重定向到其他地方 (例如,return ‘/login’)
  • 一个导航守卫抛出了一个 Error

NavigationFailureType 可获知故障类型

import { NavigationFailureType} from 'vue-router'
  • aborted:在导航守卫中返回 false 中断了本次导航。
  • cancelled: 在当前导航完成之前又有了一个新的导航。比如,在等待导航守卫的过程中又调用了 router.push。
  • duplicated:导航被阻止,因为我们已经在目标位置了。

当次路由故障检测

const navigationResult = await router.push('/my-profile')if (navigationResult) {// 导航被阻止
} else {// 导航成功 (包括重新导航的情况)this.isMenuOpen = false
}

跳转路由前,提醒页面未保存

import { NavigationFailureType, isNavigationFailure } from 'vue-router'// 试图离开未保存的编辑文本界面
const failure = await router.push('/articles/2')if (isNavigationFailure(failure, NavigationFailureType.aborted)) {// 给用户显示一个小通知showToast('You have unsaved changes, discard and leave anyway?')
}

也可用 .then 的写法

// 正在尝试访问 admin 页面
router.push('/admin').then(failure => {if (isNavigationFailure(failure, NavigationFailureType.aborted)) {failure.to.path // '/admin'failure.from.path // '/'}
})

failure 对象中的 to 和 from 都是规范化的路由地址。

全局路由故障检测

router.afterEach((to, from, failure) => {if (failure) {sendToAnalytics(to, from, failure)}
})

检测重定向

通过读取路由地址中的 redirectedFrom 属性实现

await router.push('/my-profile')
if (router.currentRoute.value.redirectedFrom) {// redirectedFrom 是解析出的路由地址,就像导航守卫中的 to和 from
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/49904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Xtrabackup备份mysql数据库

XtraBackup是一个用于MySQL和Percona Server的开源热备份工具&#xff0c;它由Percona开发。XtraBackup支持两种备份类型&#xff1a;完整备份&#xff08;full backup&#xff09;和增量备份&#xff08;incremental backup&#xff09;。 一、备份原理及优势 xtrabackup在备份…

OpenCV库学习之cv2.GaussianBlur函数

OpenCV库学习之cv2.GaussianBlur函数 一、简介 cv2.GaussianBlur 是 OpenCV 图像处理库中的一个函数&#xff0c;它用于对图像进行高斯模糊处理。高斯模糊是一种常用的图像模糊技术&#xff0c;通过高斯函数对图像进行卷积&#xff0c;实现图像的平滑效果&#xff0c;常用于去…

20240724-然后用idea创建一个Java项目/配置maven环境/本地仓储配置

1.创建一个java项目 &#xff08;1&#xff09;点击页面的create project&#xff0c;然后next &#xff08;2&#xff09;不勾选&#xff0c;继续next &#xff08;3&#xff09;选择新项目名称&#xff0c;新项目路径&#xff0c;然后Finsh&#xff0c;在新打开的页面选择…

IDEA在编译的时候报Error: java: 找不到符号符号: 变量 log lombok失效问题

错误描述 idea因为lombok的报错: java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled.Your processor is: com.sun.proxy.$Proxy8Lombok supports: sun/apple javac 1.6, ECJ 原因&#xff1a;这是由于Lombok的版本过低的…

ARM-A7通用中断服务函数-1

中断流程 保存现场-执行中断服务函数-返回现场 .S文件的修改 先看代码&#xff1a; IRQ_Handler:push {lr} /* 保存lr地址 */push {r0-r3, r12} /* 保存r0-r3&#xff0c;r12寄存器 */mrs r0, spsr /* 读取spsr寄存器 */push {r0} /* 保存spsr寄存器 */mrc p1…

分布式:RocketMQ/Kafka总结(附下载链接)

文章目录 下载链接思维导图 本文总结的是关于消息队列的常见知识总结。消息队列和分布式系统息息相关&#xff0c;因此这里就将消息队列放到分布式中一并进行处理关联 下载链接 链接: https://pan.baidu.com/s/1hRTh7rSesikisgRUO2GBpA?pwdutgp 提取码: utgp 思维导图

刷题了:150. 逆波兰表达式求值 |239. 滑动窗口最大值 |347.前 K 个高频元素

150. 逆波兰表达式求值 题目链接:https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/ 文章讲解:https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html 视频讲解:https://www.bilibili.…

crack 基于golang的多并发爆破工具

一款轻巧的内网弱口令枚举工具&#xff0c;项目地址&#xff1a;GitHub - oksbsb/crack: 支持 ftp ssh smb mysql mssql postgres 安装 ​ git clone https://github.com/yanweijin/crack go build main.go基于用法 ➜ crack git:(master) ✗ go run main.go --help …

UE4调试UE4Editor-Cmd.exe

在工作中&#xff0c;我们看到这样的构建命令&#xff1a; %EnginePath%\Binaries\Win64\UE4Editor-Cmd.exe %ClientPath%\%ProjectName%.uproject -runHotPatcher {其它参数} 我们应该如何调试UE4Editor-Cmd.exe呢&#xff1f;其实调试 UE4Editor.exe 就可以了&#xff08;参考…

1111111111111111111111

https://chat18.aichatos.xyz/#/chat/1716220931748File "D:\微信\venv\Lib\site-packages\pyautogui\__init__.py", line 228, in _couldNotImportPyScreezeraise PyAutoGUIException( pyautogui.PyAutoGUIException: PyAutoGUI was unable to import pyscreeze. (T…

LabVIEW程序员以后会不会被ai取代?

关于LabVIEW程序员未来的就业前景和AI的影响&#xff0c;可以从多个角度进行分析&#xff1a; AI对LabVIEW程序员的影响 自动化和AI辅助编程&#xff1a; AI正在迅速发展&#xff0c;可以在某些领域自动生成代码、优化代码和检测错误。对于标准化的、重复性的编程任务&#xf…

解决:Maven模块项目引入其他模块项目依赖,却无法引用对方文件异常

解决&#xff1a;Maven模块项目引入其他模块项目依赖&#xff0c;却无法引用对方文件异常 一问题描述&#xff1a;Maven模块项目引入其他模块项目依赖&#xff0c;却无法引用对方文件二问题原因&#xff1a;三解决方案&#xff1a; 一问题描述&#xff1a;Maven模块项目引入其他…

【优秀python系统毕设】基于Python flask的气象数据可视化系统设计与实现,有LSTM算法预测气温

第一章 绪论 1.1 研究背景 在当今信息爆炸的时代&#xff0c;气象数据作为重要的环境信息资源&#xff0c;扮演着关键的角色。然而&#xff0c;传统的气象数据呈现方式存在信息量庞大、难以理解的问题&#xff0c;限制了用户对气象信息的深入理解和利用。因此&#xff0c;基…

React的img图片路径怎么写

在React中&#xff0c;图片路径的写法取决于你的图片资源是如何被管理和存放的。这里有几种常见的情况和对应的写法&#xff1a; 1. 图片作为React组件的静态资源 如果你的图片文件放在React项目的public文件夹下&#xff08;这是Create React App项目的默认结构&#xff09;…

List容器

此处是带头双向链表 对于List&#xff0c;不像string、vector之类的&#xff0c;没有reserve的说法&#xff0c;也不支持[ ]和下标&#xff0c;只有一种方式遍历List也就是采用迭代器&#xff08;范围for的底层也是迭代器&#xff09;。 insert函数和erase函数(需要配合std库里…

Java入门TCP客户端和服务器应用程序 2024.7.27 22:14

下面是一个完整的示例&#xff0c;展示如何使用 Java 的 Socket 和 ServerSocket 类编写一个简单的 TCP 客户端和服务器应用程序&#xff0c;以及一个简单的聊天应用程序。代码包括客户端和服务器的实现&#xff0c;能够通过 TCP 连接进行消息交换。 1. TCP 服务器程序 首先&…

文件包含漏洞及利用

一、文件包含功能 1、文件包含的作用&#xff1a;减小代码的荣誉 2、文件包含函数&#xff1a; include 、 require 3、文件包含的方式 静态文件包含------文件名是固定的------ a.php中存在普通的字符串&#xff0c;被b.php包含&#xff0c; a.php中的字符串会直接完成输出 a…

CSS:mix-blend-mode属性(设置元素的混合模式)

目录 一、mix-blend-mode属性介绍 二、mix-blend-mode常用属性值 三、mix-blend-mode属性应用 四、文字智能适配背景 1、原始样式 2、添加混合 3、实现代码 一、mix-blend-mode属性介绍 CSS中的【mix-blend-mode属性】描述了元素的内容应该与元素的直系父元素的内容和…

C# 植物大战僵尸

Winform 版本开发 高效率、流畅植物大战僵尸 git地址&#xff1a;冯腾飞/植物大战僵尸

3. 类的生命周期

类的生命周期是指一个类被加载&#xff0c;使用&#xff0c;卸载的一个过程&#xff0c;如下图&#xff1a; 类的加载阶段&#xff1a; 加载(Loading)阶段第一步是类加载器根据类的**全限定名&#xff08;也就是类路径&#xff09;**通过不同的渠道以二进制流的方式获取字节码…