Hash地址(锚链接#)与组件之间的对应关系
<a href="#a"></a> <div id="a"></div>
location.hash
location.href
路由占位符
<router-view></router-view>
//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
- 用户在访问地址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 重定向的 字符串路径/路径对象 }} ] })
官方地址:https://router.vuejs.org/zh/guide/essentials/nested-routes.html
通过路由实现组件的嵌套展示,叫做嵌套路由
/user/foo/profile /user/foo/posts +------------------+ +-----------------+ | User | | User | | +--------------+ | | +-------------+ | | | Profile | | +------------> | | Posts | | | | | | | | | | | +--------------+ | | +-------------+ | +------------------+ +-----------------+
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值为空字符串,则这条路由规则,叫做默认子路由
把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>' }
props:true
,可以传值routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User,props:true } ]
//User.vue <div>User {{ id }}</div props:['id']
注意1:
this.$route.params
来访问路径参数(User)注意2:
this.$route.query
来访问查询参数注意3:
在浏览器中,点击链接实现导航的方式,叫做声明式导航。
如:普通网页中点击<a>
链接、vue项目中点击<router-link>
都属于声明式导航
在浏览器中,调用API方法实现导航的方式,叫编程式导航。
如:普通网页中调用location.href
跳转到新页面的方式,属于编程式导航
tip:在行内使用编程式导航时,this必须要省略,否则会报错
router.push(location, onComplete?, onAbort?)
$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)
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()
在历史记录中,前进到下一个页面
可以控制路由的访问权限
每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制。
//创建路由实例对象 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()//访问的不是后台主页,直接放行 } })
在 2.5.0+ 你可以用 router.beforeResolve
注册一个全局守卫。这和 router.beforeEach
类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身:
router.afterEach((to, from) => { // ... })
你可以在路由配置上直接定义 beforeEnter
守卫:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ] })
最后,你可以在路由组件内直接定义以下路由导航守卫:
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` } }