Vue--Router篇
1. 什么是前端路由
Hash地址(锚链接#)与组件之间的对应关系
<a href="#a"></a>
<div id="a"></div>
- Hash地址中#往后的部分就是hash地址
http://localhost:8080/#/Home - Hash地址中/往后的参数项,叫做路径参数
http://localhost:8080/#/Home
location.hash
location.href
路由占位符
<router-view></router-view>
2. 前端路由的工作方式
- 用户点击页面上的路由链接
- 导致了URL地址栏上的Hash值发生了变化
- 前端路由监听到了Hash地址的变化
- 前端路由把当前Hash地址对应的组件渲染到浏览器中
3. 简易路由
//App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
// router-index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
//创建路由的实例对象
const routes = [
//路由规则
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
4. 路由的重定向
- 用户在访问地址A的时候,强制用户跳转到地址B,从而展示特定的组件页面。
- 通过路由规则的redirect属性,指定一个新的路由地址,可以很方便地设置路由的重定向
- 重定向也是通过
routes
配置来完成,下面例子是从/a
重定向到/b
:
//router-index.js
const router = new VueRouter({
routes: [
{ path: '/a', redirect: '/b' }
]
})
- 重定向的目标也可以是一个命名的路由:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: { name: 'foo' }}
]
})
- 甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({
routes: [
{ path: '/a', redirect: to => {
// 方法接收 目标路由 作为参数
// return 重定向的 字符串路径/路径对象
}}
]
})
5. 嵌套路由
官方地址:https://router.vuejs.org/zh/guide/essentials/nested-routes.html
通过路由实现组件的嵌套展示,叫做嵌套路由
- 实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
- 通过children属性声明子路由规则
在src/router/index.js中导入需要的组件,并使用children属性声明子路由规则:
import UserProfile from './components/'
import UserPosts from './components/'
const router = new VueRouter({
routes: [
{ //父级路由规则
path: '/user',
component: User,
//子级路由规则
children: [
{
// 当 /user/:id/profile 匹配成功,
// UserProfile 会被渲染在 User 的 <router-view> 中
//访问user/profile,展示UserProfile组件
path: 'profile',
component: UserProfile
},
{
// 当 /user/:id/posts 匹配成功
// UserPosts 会被渲染在 User 的 <router-view> 中
//访问user/posts,展示UserPosts组件
path: 'posts',
component: UserPosts
}
]//子路由结束
}
]//父路由结束
})
tip=>默认子路由 如果children数组中,某个路由规则的path值为空字符串,则这条路由规则,叫做默认子路由
6. 动态路由
把Hash地址中可变的部分定义为参数项,从而提高路由规则的复用性。
在vue-router中使用英文冒号(:)来定义路由的参数项
this.$route
是路由的参数对象
this.$router
是路由的导航对象
//router/index.js
const User = {
template: '<div>User</div>'
}
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User }
]
})
//User.vue
//路由ID
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
- 当router/index.js的routes添加
props:true
,可以传值
routes: [
// 动态路径参数 以冒号开头
{ path: '/user/:id', component: User,props:true }
]
//User.vue
<div>User {{ id }}</div
props:['id']
注意1:
- Hash地址中/往后的参数项,叫做路径参数
http://localhost:8080/#/Home - 用
this.$route.params
来访问路径参数(User)
注意2:
- Hash地址中?往后的参数项,叫做查询参数
http://localhost:8080/#/Home/?name=by age=20 - 用
this.$route.query
来访问查询参数
注意3:
- 在this.$route中,path只是路径部分,fullpath是完整的路径
7. 声明式导航
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
如:普通网页中点击<a>
链接、vue项目中点击<router-link>
都属于声明式导航
8.编程式导航
在浏览器中,调用API方法实现导航的方式,叫编程式导航。
如:普通网页中调用location.href
跳转到新页面的方式,属于编程式导航
tip:在行内使用编程式导航时,this必须要省略,否则会报错
router.push(location, onComplete?, onAbort?)
注意:在 Vue 实例内部,你可以通过$router
访问路由实例。因此你可以调用this.$router.push
。
-
想要导航到不同的 URL,则使用
router.push
方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。 -
当你点击
<router-link>
时,这个方法会在内部调用,所以说,点击<router-link :to="...">
等同于调用router.push(...)
。
<button @click="gotoLogin">跳转到Home/Login</button>
methods:{
gotoLogin(){
//通过编程式API跳转页面
this.$router.push('/home/login')
}
}
router.replace(location, onComplete?, onAbort?)
- 跟
router.push
很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
<button @click="gotoLogin">跳转到Home/Login</button>
methods:{
gotoLogin(){
//通过编程式API跳转页面
this.$router.replace('/home/login')
}
}
router.go(n)
- 这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似
window.history.go(n)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)
this.$router.go(-1)
-
$router.back()
在历史记录中,后退到上一个页面 -
$router.forward()
在历史记录中,前进到下一个页面
9. 导航守卫
可以控制路由的访问权限
9.1 全局前置守卫
每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制。
//创建路由实例对象
const router = new VueRouter({ ... })
//调用路由实例对象的beforeEach方法,即可声明全局前置守卫
//每次发生路由导航跳转的时候,就会自动触发回调函数
router.beforeEach((to, from, next) => {
//next()函数表示放行的意思。
// next()
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
每个守卫方法接收三个参数:
-
to: Route
: 即将要进入的目标路由对象 -
from: Route
: 当前导航正要离开的路由 -
next: Function
: 一定要调用该方法来 resolve 这个钩子。执行效果依赖next
方法的调用参数。-
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next()函数表示放行的意思。 -
next(false)
: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from
路由对应的地址。 -
next('/')
或者next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向next
传递任意位置对象,且允许设置诸如replace: true
、name: 'home'
之类的选项以及任何用在router-link
的to
prop 或router.push
中的选项。 -
next(error)
: (2.4.0+) 如果传入next
的参数是一个Error
实例,则导航会被终止且该错误会被传递给router.onError()
注册过的回调。
-
router.beforeEach((to, from, next) => {
if (to.path === '/main'){
const token = localstorage.getItem('token')
if(token){
//访问的是后台主页,且有token的值
next()
}else{
//访问的是后台主页,但没有token的值
next('/login')
}
}
else{
next()//访问的不是后台主页,直接放行
}
})
9.2 全局解析守卫
在 2.5.0+ 你可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
9.3 全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})
9.4 路由独享守卫
你可以在路由配置上直接定义 beforeEnter
守卫:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
9.5 组件内守卫
最后,你可以在路由组件内直接定义以下路由导航守卫:
beforeRouteEnter
beforeRouteUpdate
(2.2 新增)beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
next(vm => {
// 通过 `vm` 访问组件实例
})
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
本文来自博客园,作者:1940,转载请注明原文链接:https://www.cnblogs.com/beiyi-Lin/p/15322500.html