路由
url的hash
- URL的hash也就是锚点(#), 本质上是改变window.location的href属性;
- 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新
hash的优势就是兼容性更好,在老版IE中都可以运行,但是缺陷是有一个#,显得不像一个真实的路径。
HTML5的History
history接口是HTML5新增的, 它有六种模式改变URL而不刷新页面:
- replaceState:替换原来的路径;
- pushState:使用新的路径;
- popState:路径的回退;
- go:向前或向后改变路径;
- forward:向前改变路径;
- back:向后改变路径
vue-router
使用vue-router的步骤:
- 第一步:创建路由组件的组件;
- 第二步:配置路由映射: 组件和路径映射关系的routes数组;
- 第三步:通过
createRouter
创建路由对象,并且传入routes
和history
模式; - 第四步:使用路由: 通过
<router-link>
和<router-view>
;
import {createRouter, createWebHashHistory} from 'vue-router'
const routes = [
{path:'/',redirect:'/home'}
{path:'/home',component:()=> import('../pages/Home.vue')},
{path:'/about',component:()=> import('../pages/About.vue')},
]
const router = createRouter({
routes,
history: createWebHashHistory()
})
export default router
路由懒加载:
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载:
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效;也可以提高首屏的渲染效率
component:()=> import('../pages/Home.vue')
router-link
router-link事实上有很多属性可以配置:
to
属性:- 是一个字符串,或者是一个对象
replace
属性:- 设置 replace 属性的话,当点击时,会调用
router.replace()
,而不是router.push()
;
*active-class
属性: - 设置激活a元素后应用的class,默认是
router-link-active
- 设置 replace 属性的话,当点击时,会调用
exact-active-class
属性:- 链接精准激活时,应用于渲染的
<a>
的 class,默认是router-link-exact-active;
- 链接精准激活时,应用于渲染的
动态路由基本匹配
需要将给定匹配模式的路由映射到同一个组件
在路径中使用一个动态字段来实现,我们称之为 路径参数
{
path:'/user/:id',
component:()=> import('../pages/User.vue')
}
获取动态路由的值
那么在上面动态路由中(User)如何获取到对应的值呢?
- 在template中,直接通过 $route.params获取值;
<template> <div>{{ $route.params.id }}</div> </template>
- 在created中,通过 this.$route.params获取值;
created(){ console.log(this.$route.params.id); }
- 在setup中,我们要使用 vue-router库给我们提供的一个hook useRoute;
- 该Hook会返回一个Route对象,对象中保存着当前路由相关的值
setup(){ const route = useRoute(); console.log(route); console.log(route.params.id); }
- 在created中,通过 this.$route.params获取值;
对于没有匹配到的路由,我们通常会匹配到固定的某个页面
比如NotFound的错误页面中,这个时候我们可编写一个动态路由用于匹配所有的页面
{
path:'/:pathMatch(.*)',
component: ()=> import('../pages/NotFound.vue')
}
同时我们可以通过 $route.params.pathMatch
获取到传入的参数:
<h2>Not Found:{{$route.params.pathMatch}}</h2>
此时输出 Not Found:user/hahah/123
匹配规则加*
path:'/:pathMatch(.*)*'
此时输出 Not Found:["user","hahah","123"]
router-view
实现路由的嵌套,使用 router-view 来占位之后需要渲染的组件
//嵌套配置
{
path:'/home',
component:()=> import('../pages/Home.vue'),
children:[
{
path:'',
redirect:'/home/product'
},
]
}
代码的页面跳转
jumpToProfile(){
//this.$route.push('/profile')
this.$route.push({
path:'/profile',
query:{name:'hahah', age:18}
})
}
其中的参数通过KaTeX parse error: Expected '}', got 'EOF' at end of input: … `<h2>query: {{route.query.name}}`
在setup中,可以通过 useRouter
来实现页面跳转
const router = useRouter()
const jumpToProfile = ()=>{
router.replace('./profile')
//此时是替换当前位置,上一个页面不可回退,而push是压入一个新的页面
}
路由中的作用域插槽
router-link的v-slot
<router-link to="/about" v-slot="props" custom>
<p>href:{{props.href}}</p>
<p @click="navigate">跳转</p>
</router-link>
- v-slot的props也可以解构—>
v-slot="{href, route, ...}"
- 使用
custom
表示我们整个元素要自定义,如果不写,那么自定义的内容会被包裹在一个 a 元素中; - 使用v-slot来作用域插槽来获取内部传给我们的值:
href
:解析后的 URL;route
:解析后的规范化的route对象;navigate
:触发导航的函数;isActive
:是否匹配的状态;isExactActive
:是否是精准匹配的状态
router-view的v-slot
<router-view v-slot="props">
<transition name="haha">
<keep-alive>
<component :is="props.component"></component>
</keep-alive>
</transition>
</router-view>
- component为要渲染的组件
- 此时的props也可解构---->
v-slot="{component}"
动态路由
动态添加路由
使用方法 addRoute
顶级路由配置:
const categoryRoute = {
path:'/category',
component:()=>import('../pages/Category.vue')
}
router.addRoute(categoryRoute)
子路由配置:
const homeMomentRoute = {
path:'moment',
component: ()=>import(''../pages/homeMoment.vue')
}
router.addRoute('home', homeMomentRoute)
动态删除路由
- 方式一:添加一个
name
相同的路由;
route.addRoute({path:'/about', name:'about', component:About})
route.addRoute({path:'/other', name:'about', component:Home})
相当于替换之前已添加的路由,两者具有相同的名字并且是唯一的
- 方式二:通过
removeRoute
方法,传入路由的名称;
route.addRoute({path:'/about', name:'about', component:About})
router.removeRoute('about')
- 方式三:通过
addRoute方法的返回值
回调
const removeRoute = router.addRoute(routeRecord)
removeRoute()
此时会删除路由如果该路由存在
路由其他方法:
router.hasRoute()
:检查路由是否存在。router.getRoutes()
:获取一个包含所有路由记录的数组
路由导航守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航
全局的前置守卫beforeEach
是在导航触发时会被回调的:
- 它有两个参数:
- to:即将进入的路由Route对象;
- from:即将离开的路由Route对象;
- 它有返回值:
- false:取消当前导航;
- 不返回或者undefined:进行默认导航;
- 返回一个路由地址:
- 可以是一个string类型的路径;
- 可以是一个对象,对象中包含path、query、params等信息;
- 可选的第三个参数:next
- 在Vue2中我们是通过next函数来决定如何进行跳转的;
- 但是在Vue3中我们是通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next
router.beforeEach((to,from)=>{
console.log(to);
console.log(from);
return false;
})
可以用来实现登录守卫功能—每次跳转都会判断是否是去登录页面,如果不是的话是否本地存储了token密钥,如果没有则跳转登录
完整的导航解析流程
-
导航被触发
-
在失活的组件里调用 beforeRouteLeaves 守卫
-
调用全局的 beforeEach 守卫
-
在重用的组件里调用 beforeRouteUpdate 守卫
-
在路由配置里调用 beforeEnter
-
解析异步路由组件
-
在被激活的组件里调用 beforeRouteEnter
-
调用全局的beforeResolve 守卫
-
导航被确认
-
调用全局的 afterEach 钩子
-
触发 DOM 更新
-
调用 beforeRouteEnter 守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入