Vue核心插件之Vue Router

简介

Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。

单页应用与多页应用区别:

  • 单页应用
    整个webapp就一个html文件,刷新页面会请求一个HTML文件,切换页面的时候,并不会发起新的请求一个HTML文件,只是页面内容发生了变化.
    原理: js感知url变化,当url变化时,使用js动态把当前的页面内容清除掉,再把请求的页面内容(新组件)挂载到页面(根节点)上.
    特点:页面切换快(页面切换无需http请求),但首屏时间稍慢(请求html以及js),SEO差(搜索引擎只认识HTML内容不认识JS内容)
    解决方案: vue服务端渲染技术
  • 多页应用
    每一次页面跳转的时候,后台服务器都会返回一个新的html文件,路由由后端来写, 这种类型的网站称为多页面网站(多页面应用)
    特点: 首屏时间快,SEO效果好,但页面切换慢

起步:
使用vue,通过组件组合来组成应用程序,然后将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们.

App.vue

<template>
  <div id="app">
    
    
    <router-view/>
  div>
template>

javascript

// 1. 定义 (路由) 组件,可以从其他文件 import 进来
const Foo = {
      template: '
foo
'
} const Bar = { template: '
bar
'
} // 2. 定义路由 每个路由应该映射一个组件 const routes = [ { path: '/foo', component: Foo }, { path: '/bar', component: Bar } ] // 3 router/index.js import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) // 创建 router 实例,然后传 `routes` 配置,还有其它配置如:mode(路由模式) const router = new VueRouter({ routes // (缩写) 相当于 routes: routes }) // 4.main.js // 创建和挂载根实例 通过 router 配置参数注入路由, 从而让整个应用都有路由功能 // vuex store import store from '@/store/index' // 菜单和路由设置 import router from './router' new Vue({ router, store }).$mount('#app)

this.$routerthis.$route的区别

  • this.$router: 是Vue Router的实例,相当于一个全局的路由器对象,包含属性、方法和子对象,如push()、go()、history对象等
  • this.$route: 用于访问当前路由对象, 如: 当前路由的name、path、query、params等有关属性

核心概念

路由模式

路由: 根据不同的url地址展现不同的内容或页面. 前端路由更多用在单页应用(SPA)
url组成部分:
Vue核心插件之Vue Router_第1张图片
两种路由对比:

hash(默认) history(mode: history)
url http:// abc.com/#/user/20 有#,不美观 http:// abc.com/user/20 美观
兼容性 兼容低版本浏览器以及IE浏览器 HTML5新推出的API
特点 hash变化会触发网页跳转,即浏览器的前进,后退;不会导致浏览器向服务器发出请求,也就不会刷新页面;会触发hashchange事件 用url规范的路由,但跳转时不发送请求,不自动刷新页面; 因为不发送请求, url地址变化, 一旦页面一手动刷新就会找不到这个页面,报404,需要服务器端做点手脚,将不存在的路径请求重定向到入口文件(index.html)
主要内容 hashchange事件 pushState和replaceStateAPI; onpopstate 事件

实现原理:检测 url 的变化,截获 url 地址,然后解析来匹配路由规则

hash模式: hashchange事件监听hash变化 源码

/**
 * 添加 url hash 变化的监听器
 */
setupListeners () {
     
  const router = this.router

  /**
   * 每当 hash 变化时就解析路径
   * 匹配路由
   */
  window.addEventListener('hashchange', () => {
     
    const current = this.current
    /**
     * transitionTo: 
     * 匹配路由
     * 并通过路由配置,把新的页面 render 到 ui-view 的节点
     */
    this.transitionTo(getHash(), route => {
     
      replaceHash(route.fullPath)
    })
  })
}

history模式: window.onpopstate监听; pushState 和 replaceState,通过这两个 API 可以改变 url 地址且不会发送请求 源码

export class HTML5History extends History {
     
  constructor (router, base) {
     
    super(router, base)
    /**
     * 原理还是跟 hash 实现一样
     * 通过监听 popstate 事件
     * 匹配路由,然后更新页面 DOM
     */
    window.addEventListener('popstate', e => {
     
      const current = this.current

      // Avoiding first `popstate` event dispatched in some browsers but first
      // history route not updated since async guard at the same time.
      const location = getLocation(this.base)
      if (this.current === START && location === initLocation) {
     
        return
      }

      this.transitionTo(location, route => {
     
        if (supportsScroll) {
     
          handleScroll(router, route, current, true)
        }
      })
    })
  }

  go (n) {
     
    window.history.go(n)
  }

  push (location, onComplete, onAbort) {
     
    const {
      current: fromRoute } = this
    this.transitionTo(location, route => {
     
      // 使用 pushState 更新 url,不会导致浏览器发送请求,从而不会刷新页面
      pushState(cleanPath(this.base + route.fullPath))
      onComplete && onComplete(route)
    }, onAbort)
  }

  replace (location, onComplete, onAbort) {
     
    const {
      current: fromRoute } = this
    this.transitionTo(location, route => {
     
      // replaceState 跟 pushState 的区别在于,不会记录到历史栈
      replaceState(cleanPath(this.base + route.fullPath))
      onComplete && onComplete(route)
    }, onAbort)
  }
}
export function cleanPath (path: string): string {
     
  return path.replace(/\/\//g, '/')
}

路由配置

  • 动态路由
    把某种模式匹配到的所有路由,全都映射到同个组件. 例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来实现

    const router = new vueRouter({
           
      routes: [
        //动态路径参数,以冒号开头,能命中`user/10`, `user/20`等格式的路由  
        {
           path: 'user/:id', component: User}
      ]
    })
    // 获取参数
    this.$route.params.id 
    

    注意: 当使用路由参数时,例如从 /user/10 导航到 /user/20,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。复用也意味着组件的生命周期钩子不会再被调用

    如果想对路由参数的变化作出响应的话,可以监测$route 对象或 beforeRouteUpdate 导航守卫:

    
    const User = {
           
      template: '...',
      // 监测
      watch: {
           
       '$route' (to, from) {
           
          // 对路由变化作出响应...
        }
      },
      // 或导航守卫
      beforeRouteUpdate (to, from, next) {
           
        // react to route changes...
        // don't forget to call next()
        next()
      }
    }
    
  • 捕获所有路由或 404 Not found 路由
    想匹配任意路径,我们可以使用通配符(*),路由 { path: '*' }通常用于客户端 404 错误

    {
           
      path: '*',
      name: '404',
      component: () => import('@/pages/error-page-404')
    }
    //当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。
    //它包含了 URL 通过通配符被匹配的部分
    // 给出一个路由 { path: '*' }
    this.$router.push('/non-existing')
    this.$route.params.pathMatch // '/non-existing'
    

    注: 含有通配符的路由应该放在最后

  • 嵌套路由: children 配置嵌套多层路由

  • 命名视图: 同级展示多个视图,而不是嵌套展示

  • 命名路由: 以一个名称(name)来标识一个路由

  • 组件传参: 在组件中使用 $route 会使之与其对应路由形成高度耦合,使用 props 将组件和路由解耦

  • 路由懒加载(按需加载): 当路由被访问的时候才加载对应组件

    const Foo = () => import('./Foo.vue')
    

路由导航

声明式导航 编程式导航
this.$router.push(...)
this.$router.replace(...)
router.go(n) 在 history 记录中向前(n为正整数)或者后退(n为负整数)多少步

push()、replace()方法所带参数可以是一个字符串路径,或者一个描述地址的对象
注意: 如果提供了 path,params 会被忽略

const userId = '123'
// 字符串
router.push('home')
// 对象
router.push({
      name: 'user', params: {
      userId }}) // -> /user/123
router.push({
      path: `/user/${
       userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({
      path: '/user', params: {
      userId }}) // -> /user

其它

  • 导航守卫
    vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航,共三种导航守卫类型: 全局的、单个路由配置的、组件级的.
    全局守卫:

    路由钩子 描述
    router.beforeEach((to, from, next) => { }) 全局前置守卫,可用于路由拦截,权限验证,撤销请求等
    router.beforeResolve() 全局解析守卫
    router.afterEach((to, from) => {}) 全局后置钩子

    每个守卫方法接收三个参数:

    参数 描述
    to:Route 即将要进入的目标 路由对象
    from:Route 当前导航正要离开的路由
    next: Function 调用 next 方法,确保钩子被 resolved. 四种调用参数: next() 进行下一钩子、next(false): 中断当前导航、next(’/’): 导航中断,跳转一个新导航、next(error): 导航终止且该错误会被传递给 router.onError() 注册过的回调

    路由守卫: beforeEnter

    const router = new VueRouter({
           
      routes: [
        {
           
           path: '/foo',
           component: Foo,
           beforeEnter: (to, from, next) => {
           
             // ...
           }
         }
       ]
    })
    

    组件守卫

    路由钩子 描述
    beforeRouteEnter (to, from, next) {}) 在渲染该组件的对应路由被 confirm 前调用 .当守卫执行前,组件实例还没被创建, 不!能!获取组件实例 this
    beforeRouteUpdate (to, from, next) {}) 在当前路由改变,但是该组件被复用时调用,可以访问组件实例 this. 用途: 对动态路由参数的变化作出监听
    beforeRouteLeave (to, from, next) {}) 导航离开该组件的对应路由时调用,可以访问组件实例 this
  • 路由元信息: 定义路由的时候可以配置 meta 字段

  • 过渡动效: 给路由设置过渡效果

  • 数据获取: 进入某个路由后,从服务器获取数据

  • 滚动行为: 自定义路由切换时页面如何滚动

  • Vue Router API

你可能感兴趣的:(VUE,vue,vue.js,html,前端)