参考:丁丁的哔哩哔哩
vue router
路由注意点:
- js根据路径的变化显示不同的内容;
- 路由核心:改变url,但是页面不进行整体刷新。
- 路由表,是一个映射表,一个路由就是一组映射关系,key:value。key:表示路由,value:可以为function或者Component组件
<!-- vue-router是基于路由和组件的,路由是用来设定访问路径,将路径和组件映射起来,-->
import { createMemoryHistory, createRouter } from 'vue-router'
// 定义路由组件
import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'
// 定义路由表
const routes = [
{ path: '/', component: HomeView },
{ path: '/about', component: AboutView },
]
// 创建路由实例并传递"routes"配置
const router = createRouter({
history: createMemoryHistory(),
routes,
})
<template>
<h1>Hello App!</h1>
<p>
<strong>Current route path:</strong> {{ $route.fullPath }}
</p>
<nav>
<!--通过传递 'to' 来指定链接-->
<!--<router-link> 将呈现一个带有正确"href"属性的<a>标签 -->
<RouterLink to="/">Go to Home</RouterLink>
<RouterLink to="/about">Go to About</RouterLink>
</nav>
<main>
<RouterView />
</main>
</template>
RouterLink
使用一个自定义组件 router-link 来创建链接。这使得 vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。
它的"to"属性指向路由,根据index配置的路由表,对应要展示的组件。
RouterView
路由出口,占位符。路由匹配到的组件将渲染在这里
带参数的动态路由匹配
路径参数:
import User from './User.vue'
// 这些都会传递给 `createRouter`
const routes = [
// 动态字段以冒号开始
{ path: '/users/:id', component: User },
]
如何使用:
// 会映射到同一个路由
path = "/users/johnny"
path = "/users/jolyne"
组件user.vue:
import {useRoute} from "vue-router";
// 获取当前活跃的路由对象的路径参数,可以将路径参数传入接口用于获取数据
console.log(useRoute().params.id)
404页面
404页面,匹配上述路径外的所有路径
const routes = [
{ path: '/',
component: HomeView
},
{ path: '/about',
component: AboutView
},
{ path: '/user/:id',
component: UserView
},
{ path: '/:path(.*)',// 正则表达式,匹配上述路径外的所有路径
component: () => import('@/views/404.vue')
}
]
动态路由参数的正则限制
- 动态路由的参数一定是数字, /news/456
{ path: '/news/:id(\\d+)',
component: () => import('@/views/news.vue')
},
- 有多个参数, /news/456/789/kkk
{ path: '/news/:id+',
component: () => import('@/views/news.vue')
},
- 参数可有可无 ,参数不可以重复叠加, /news/456/789 或者 /news
{ path: '/news/:id*',
component: () => import('@/views/news.vue')
},
- 参数可有可无,但是参数不可以重复叠加
{ path: '/news/:id?',
component: () => import('@/views/news.vue')
},
嵌套路由
<!-- App.vue -->
<template>
<router-view />
</template>
<!-- User.vue -->
<template>
<div class="user">
<h2>User {{ $route.params.id }}</h2>
<router-view />
</div>
</template>
<!-- index.ts -->
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
// 当 /user/:id/profile 匹配成功
// UserProfile 将被渲染到 User 的 <router-view> 内部
path: 'profile',
component: UserProfile,
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 将被渲染到 User 的 <router-view> 内部
path: 'posts',
component: UserPosts,
},
],
},
]
编程式导航
- 声明式:
<router-link :to="...">
- 编程式:
router.push(...)
// 字符串路径
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' })
替换当前位置
在导航时不会向 history 添加新记录,而是替换原先页面;浏览器左上方的前进、后退按钮失效
- 声明式:
<router-link :to="..." replace>
- 编程式:
router.push({ path: '/home', replace: true })
// 相当于
router.replace({ path: '/home' })
横跨历史
// 向前移动一条记录,与 router.forward() 相同
router.go(1)
// 返回一条记录,与 router.back() 相同
router.go(-1)
// 前进 3 条记录
router.go(3)
// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)
命名路由: 给路由起个名字,name属性
const routes = [
{
path: '/user/:username',
name: 'profile',
component: User
}
]
<router-link :to="{ name: 'profile', params: { username: 'erina' } }">
User profile
</router-link>
命名视图: 访问一个路径,同时 (同级) 展示多个视图
<router-view name="LeftSidebar" />
<router-view />
<router-view name="RightSidebar" />
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
},
},
],
})
重定向
- 一般形式:
const routes = [
{
path: '/home', redirect: '/'
}
]
- 重定向的目标也可以是一个命名的路由:
const routes = [
{
path: '/home', redirect: { name: 'homepage' }
}
]
- 一个方法
const routes = [
{
// /search/screens -> /search?q=screens
path: '/search/:searchText',
redirect: to => {
// 方法接收目标路由作为参数
// return 重定向的字符串路径/路径对象
return { path: '/search', query: { q: to.params.searchText } }
},
},
{
path: '/search',
// ...
},
]
别名 alias
将 / 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。
const routes = [
{
path: '/',
alias: '/home',
component: Homepage
}
]
多个别名:数组形式
const routes = [
{
path: '/users',
component: UsersLayout,
children: [
// 为这 3 个 URL 呈现 UserList
// - /users
// - /users/list
// - /people
{ path: '', component: UserList, alias: ['/people', 'list'] },
],
},
]
将 props 传递给路由组件
之前的示例:
使用$route.params获取路径参数
<!-- User.vue -->
<template>
<div>
User {{ $route.params.id }}
</div>
</template>
现在的示例:
通过声明 prop 来删除对 $route 的直接依赖:
const routes = [
{
path: '/user/:id',
component: User,
props: true
}
]
使用defineProps来声明id属性
<!-- User.vue -->
<script setup>
defineProps({
id: String
})
</script>
<template>
<div>
User {{ id }}
</div>
</template>
命名视图
对于有命名视图的路由,你必须为每个命名视图定义 props 配置:
const routes = [
{
path: '/user/:id',
components: { default: User, sidebar: Sidebar },
props: { default: true, sidebar: false }
}
]
在User.vue中可以使用defineProps获取id;而在Sidebar.vue使用defineProps获取不到id
不同的历史模式
- Hash 模式
- HTML5 模式
两者区别:一个有“#”号,一个没有
导航守卫
全局前置守卫
const router = createRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
// 返回 false 以取消导航
// return false
next() // 放行
})
每路守卫(路由独享的守卫)
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
组件内部类似生命周期函数的守卫
<script>
export default {
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用,通常用来预防用户在还未保存修改前突然离开
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
}
</script>
beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。
但可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数:
const age = 18;
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
// 例如 vm.age
})
}
路由懒加载
静态导入:全部导入
路由懒加载:用到时再加载
// 将
// import UserDetails from './views/UserDetails.vue'
// 替换成
// const UserDetails = () => import('./views/UserDetails.vue')
const router = createRouter({
// ...
routes: [
{ path: '/users/:id', component: () => import('./views/UserDetails.vue') },
],
})