Skip to content

vue-router ​

核心思想 ​

  • 策略1,监听哈希变化,触发变化
  • 利用 history API, 监听 hash 变化。

监听路由变化,找到对应的组件,然后渲染。

简易的 vue-router ​

理解了核心思想之后,来实现一个简易版的 vue-router。vue-router 的入口和核心的两个组件 router-link, router-view。

混入插件,执行 install 函数,在 beforeCreated 钩子中,挂载 options 中的 router。实例在创建时即可访问到 router,另外就是 install 时挂载 router-link 和 router-view 组件。

第一步vue-router的使用 ​

js
import router from 'vue-router'
new Vue({
  router
})
js
let _vue
class Router {
  constructor(options) {
    this.$options = options
    this.current = window.location.hash.slice(1) || '/'
    // 缓存path和route映射关系
    this.routeMap = {}
    this.$options.routes.forEach(
      route => {
        this.routeMap[route.path] = route
      }
    )

    // 监控url变化
    window.addEventListener('hashchange', this.onHashChange.bind(this))
    window.addEventListener('load', this.onHashChange.bind(this))
  }

  onHashChange() {
    this.current = window.location.hash.slice(1)
  }
}
Router.install = function(Vue) {
  _vue = Vue
  Vue.mixin({
    beforeCreated() {
      if(this.$options.router) {
        Vue.prototype.$router = this.$options.router
      }
    }
  })
  Vue.component('router-link', {
    props: {
      to: {
        type: String,
        required: true
      }
    },
    render(h) {
      return h('a',{
        attrs: {
          href: '#' + this.to
        }
      }, this.$slots.default)
    }
  })
  Vue.component('router-view', {
    render(h) {
      let component = null
      const route = this.$router.$options.routes.find(route => route.path == this.router.current)
      if (route) {
        component = route
      }
      h(component)
    }
  })
}
export default VueRouter

一些常见问题 ​

vue-router 有哪些组件? ​

<router-link> <router-view> <keep-alive>

active-class 是哪个组件的属性? ​

<router-link>,终端属性,用来做选中样式的切换,当router-link标签被点击时将会应用这个样式

动态路由与传值 ​

js
{
  path: '/details/:id'
  name: 'Details'
  component:() => import('xxxxx')
}

vue-router 有哪几种导航钩子? ​

全局前置守卫 ​

js
const router = new VueRouter({})
router.beforeEach((to, from, next) = {
  // to do somethings
})
  • to:Route, 代表要进入的目标
  • from:Route, 代表当前正要离开的路由
  • next:Function, 必须需要调用的方法,具体的执行效果则依赖 next 方法调用的参数
  • next(): 进入管道中的下一个钩子,如果全部的钩子执行完了,则导航的状态就是 confirmed(确认的)

全局后置钩子 ​

js
router.afterEach((to, from) = {
 // to do somethings
})
  • 后置钩子并没有 next 函数,也不会改变导航本身。
  • 路由独享钩子
js
const router = new VueRouter({
  routes: [
    {
      path: '/home',
      component: Home,
      beforeEnter: (to, from, next) = {
        // to do somethings
        // 参数与全局守卫参数一样
     }
    }
  ]
})

$route 和 $router 的区别是什么? ​

  • router 为 VueRouter 的实例,是一个全局路由对象,包含了路由跳转的方法、钩子函数等。
  • route 是路由信息对象||跳转的路由对象,每一个路由都会有一个 route 对象,是一个局部对象,包含 path,params,hash,query,fullPath,matched,name 等路由信息参数。

vue-router 响应路由参数的变化 ​

  • 用 watch 检测
js
// 监听当前路由发生变化的时候执行
watch: {
  $route(to, from){
    console.log(to.path)
    // 对路由变化做出响应
  }
}
  • 组件内导航钩子函数
js
beforeRouteUpdate(to, from, next){
  // to do somethings
}

vue-router 的两种模式 ​

  • hash

原理是 onhashchage 事件,可以在 window 对象上监听这个事件

js
window.onhashchange = function(event){
  console.log(event.oldURL, event.newURL)
  let hash = location.hash.slice(1)
}
  • history
  • 利用了 HTML5 History API 中新增的 pushState() 和 replaceState() 方法。
  • 需要后端配置支持。

vue-router 实现路由懒加载 ​

把不同路由对应的组件分割成不同的代码块,然后当路由被访问时才加载对应的组件即为路由的懒加载,可以加快项目的加载速度,提高效率

js
const router = new VueRouter({
  routes: [
    {
      path: '/home',
      name: 'Home',
      component:() => import('xxxxx')
    }
  ]
})

vue-router 执行顺序 ​

  1. 导航被触发
  2. 在失活的组件里调用离开守卫
  3. 调用全局的beforeEach组件
  4. 在重用的组件里调用beforeRouteUpdate组件
  5. 在路由配置里调用beforeEnter组件
  6. 解析异步路由组件
  7. 在被激活的组件里面调用beforeRouterEnter
  8. 调用全局的beforeResolve守卫
  9. 导航被确认
  10. 调用全局的afterEach钩子
  11. 触发DOM更新
  12. 用创建好的实例调用beforeRouterEnter守卫中传给 next的回调函数

Released under the MIT License.