路由基本概念

  1. 后端路由:对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源。
  2. 前端路由:对于单页面应用,只要通过URL中的hash(#号)来实现不同页面之间的切换,同时hash有一个特点:HTTP请求中不会包含hash相关的内容;
  3. 在单页面应用程序中,这种通过hash改变切换页面的方式,乘坐前端路由(区别于后端路由

    在 Vue 中使用 vue-router

  4. 导入 vue-router 组件类库 js文件

  5. 使用 router-link 组件来导航

    1. <router-link to="/login">登录</router-link>
    2. <router-link to="/register">注册</router-link>
  6. 使用 router-view组件来显示匹配到的组件

    1. <!-- to="/login" -->
    2. <router-view>
    3. <!-- 显示登录组件的内容 -->
    4. <router-view>
    1. // 路由组件的配置和匹配规则
    2. new Vue({
    3. router: new VueRouter({ // 路由对象实例
    4. mode:'', // 1. hash 2. history
    5. routes: [ // 路由匹配规则
    6. { path: '/', redirect: '/login' }, // 默认路由定义
    7. { path: '/login', component: login },
    8. { path: '/register', component: register },
    9. ],
    10. linkActiveClass: 'my-active', // 自定义链接激活时候的类名
    11. }),
    12. })

    在路由规则中定义参数(路径参数)

  7. query方式传参

  8. params方式传参 ```html

    Hello App!

    ## 路径参数 会被设置到 ‘this.$route.query’ 登录 ## 路径参数 会被设置到 ‘this.$route.params’ 注册 注册

  1. ```javascript
  2. // js 代码
  3. new Vue({
  4. router: new VueRouter({ // 路由对象实例
  5. routes: [ // 路由匹配规则
  6. { path: '/', redirect: '/login' },
  7. { path: '/login', component: login, name: 'ytf' }, // query 方式传参,不需要修改匹配规则
  8. { path: '/register/:id/:name', component: register }, // params 传参,需要 定义 匹配规则
  9. ],
  10. }),
  11. })
  12. // 数传递后,可以在各自的组件定义中,在 created 钩子函数中 拿到:
  13. // this.$route.query.id
  14. /// his.$route.params.id

当使用路由参数时间,例如从 /user/foo 导航到 /user/bar 原来的组件会被复用 因为两个路由都渲染同个组件 这也意味着 组件的生命周期钩子函数不会再被调用。 复用组件时,想要对路由参数变化做出响应,可以使用 watch 监听$route 对象 或者使用 beforeRouterUpdate 导航守卫

vue-router 的嵌套路由

  1. const router = new VueRouter({
  2. routes: [
  3. { path: '/user/:id', component: User,
  4. children: [
  5. {
  6. // 当 /user/:id/profile 匹配成功,
  7. // UserProfile 会被渲染在 User 的 <router-view> 中
  8. path: 'profile',
  9. component: UserProfile
  10. },
  11. {
  12. // 当 /user/:id/posts 匹配成功
  13. // UserPosts 会被渲染在 User 的 <router-view> 中
  14. path: 'posts',
  15. component: UserPosts
  16. }
  17. ]
  18. }
  19. ]
  20. })

vue-router 动态路由匹配

  1. <router-link to="/user/1">user1</router-link>
  2. <router-link to="/user/2">user2</router-link>
  3. <router-link to="/user/3">user3</router-link>
  1. // 父组件中 动态路由匹配
  2. var router = new VueRouter({
  3. routes: [
  4. // 动态路径参数,以冒号开头,占位符
  5. { path: '/user/:id', component: User }
  6. ]
  7. })
  1. // 匹配到的页面中
  2. {{$route.params.id}} 得到 传递的 id 参数

路由组件传递参数

$route与对应路由形成高度耦合,不够灵活,所以可以使用 props 将组件和路由解耦

  1. const user = new VueRouter({
  2. routes: [
  3. // case 1. props 的值 为 布尔类型
  4. {path:'/user/:id', components: User, props: true}
  5. // case 2 : props 的值 为对象属性
  6. {path:'/user/:id', components: User, props: {uname: 'tomy', id: '12'}}
  7. // case 3: props 的值 为 函数类型
  8. {path:'/user/:id', components: User,props: route => ({uname: 'tomy', age: '12', id: route.params.id })
  9. }
  10. ]
  11. })
  12. // 对应的路由组件中
  13. const User = {
  14. props: ['id'] // case 1 : 使用 props 接收 路由参数
  15. props: ['uname', 'age'] // case 2 : 接收对象形式的 props
  16. props: ['uname', 'age', 'id'] // case 3 : 接收函数形式的 props
  17. template: '<div>ID: {{id}}</div>' // 使用路由参数
  18. }

vue-router 命名路由

  1. var router = new VueRouter({
  2. routes: [
  3. // 动态路径参数,以冒号开头,占位符
  4. { path: '/user/:id', component: User, name: 'user' }
  5. ]
  6. })
  7. <route>
  1. <router-link to="/user/1">user1</router-link>
  2. <route-link :to="{name: 'user',params: {id: 007}}">User</route-link>

扩展_命名视图

  1. // app.vue
  2. <div id='app'>
  3. <div id='nav'>
  4. <router-link :to="{name: 'home'}">Home</router-link>
  5. <router-link :to="{name: 'about'}">about</router-link>
  6. </div>
  7. <router-view /> <!-- # 加载默认视图里的组件 -->
  8. <router-view name='email' /> <!-- # 加载 email 命名视图中的组件 -->
  9. <router-view name='tel' /> <!-- # 加载 tel 命名视图中的组件 -->
  10. </div>
  1. // router.js
  2. {
  3. path: '/named_views',
  4. components:{
  5. default: () => import('@/views/child.vue'),
  6. email: () => import('@views/email.vue'),
  7. tel:() => import('@views/tel.vue')
  8. }
  9. }

vue-router 编程式导航

$router.push(location)
  1. ## 字符串
  2. router.push('home')
  3. ## 命名路由
  4. $router.push({name: 'user', params: {id: 007} } )
  5. ## 带查询参数 /user?name=jack
  6. $router.push({name: 'user', query: {name: 'jack'} } )
  7. // 使用 path 标识跳转的路径的时候,后面的参数无效,但是可以使用 模板字符串进行传递参数
  8. ## 对象形式的传参
  9. $router.push({path: '/user', query: {name: 'jack'} } )
  10. ## 设置 查询参数
  11. this.$http.post('v1/user/select-stage', {stage: stage})
  12. .then(({data: {code, content}})=>{
  13. if(code === 0){
  14. // 对象
  15. this.$router.push({path: '/home'})
  16. }else if(code === 10){
  17. // 带查询参数 变成 /login?stage=stage
  18. this.$router.push({path: '/login', query: {stage: stage }})
  19. }
  20. })
  21. ## 设置查询参数对象
  22. let queryData = {}
  23. if(this.$route.query.stage){
  24. queryData.stage = this.$route.query.stage
  25. }
  26. if(this.$route.query.url){
  27. queryData.url = this.$route.query.url
  28. }
  29. this.$router.push({path: '/my/profile', query: queryData })
  30. ## 获取参数, 两种常用方式: params query
  31. // 传递的时候 path 和 query 配套, name 和 params 配套
  32. this.$router.params.xxx
  33. this.$router.query.xxx

router.go(n)

router.replace()

路由守卫

全局守卫

  • beforeEach(to, from, next){ } 前置守卫
  • afterEach(to, from){ } 后置守卫
  • beforeResolve() 导航被确认之前,所有守卫钩子 都触发过了,才触发这个

    1. // router.js
    2. Vue.use(Router)
    3. const router = new Router({
    4. routes
    5. })
    6. const HAS_LOGINED = true
    7. router.beforeEach((to, from, next) => {
    8. if(to.name != 'login'){
    9. if(HAS_LOGINED) next()
    10. else next({name: 'login'})
    11. }else{
    12. if(HAS_LOGINED) next({name: 'home'})
    13. else next()
    14. }
    15. })
    16. router.afterEach((to, from)=>{
    17. // loading 操作
    18. })
    19. export default router

    组件内的守卫

    在路由组件内直接定义。

  • beforeRouteEnter(to, from, next){ }

  • beforeRouteUpdate(to, from, next){ }
  • beforeRouteLeave(to, from, next){ }

    1. // 组件中的js
    2. export default {
    3. name: 'home-page',
    4. beforeRouteEnter(to, from, next){
    5. // 路由触发,但是没有进入到 页面 之前, this 不可用噢
    6. console.log(to.name)
    7. next(vm => {
    8. // vm 就是组件的实例 ,在这里可以使用 this
    9. }) // 执行跳转操作
    10. },
    11. beforerouteUpdate(to, from, next){
    12. // 组件 路由发生变化,组件被复用,可以访问 this
    13. },
    14. beforeRouteLeave(to, from, next){
    15. // 路由 触发 离开页面 之前
    16. // 用途:提示 未保存页面,确认离开否
    17. const leave = confirm('确认离开吗?')
    18. if(leave) next()
    19. else next(false)
    20. }
    21. }

    组件独享的守卫

    在路由配置上定义守卫

  • beforeEnter(to, from, next){ }

    1. // router.js 中的 路由规则配置
    2. {
    3. path: '/',
    4. name: 'home',
    5. component: Home,
    6. beforeEnter: (to, from, next)=>{
    7. if(from.name === 'login') console.log('this page is from login_page')
    8. else console.log('not from login page')
    9. next() // 执行跳转
    10. }
    11. }

    路由元信息

    在路由规则上定义元信息

    1. // router.js
    2. router.beroreEach((to, from, next)=>{
    3. if(to.meta && to.meta.title){
    4. // 设置 title
    5. window.document.title = to.meta.title
    6. }
    7. })
    8. routes:[
    9. {
    10. path: '/',
    11. name: 'home',
    12. meta: {
    13. title: '' // 设置 title
    14. }
    15. }
    16. ]