Vue路由实现、路由导航、路由模式

1.$router和$route区别

    router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象,和router-link跳转一样,this.$router.push会往history栈中添加一个新的记录。

    route相当于当前正在跳转的路由对象,可以从里面获取name,path,params,query等。

2.vue路由实现原理

    通过改变 URL,在不重新请求页面的情况下,更新页面视图。

    Location对象的属性

    

    Location对象的方法

    

    H5中的History对象的属性(部分)

    

    H5中的History对象的方法(部分)

    

    其中pushState方法和replaceState方法可以分别增加和替换掉一条记录(必须同源),而不会重新加载页面。window.location.hash和window.history.pushState(或replaceState)唯一的不同是通过hash改变url带入#,而后者不会。而Vue 路由的两种模式就是基于location和history这2个对象的!

    ps:注意这里可以通过重写pushstate和replacestate实现对history模式路由的监听

    最后说下两者的应用场景,如果hash模式F5刷新是不会向服务端请求#后面的url的,而history模式会,如果服务端没做处理,很容易出现404!

3.vue路由导航钩子

    1.全局导航钩子

        主要有两种钩子:前置守卫、后置钩子

      注册一个全局前置守卫:

const router = new VueRouter({ ... });
router.beforeEach((to, from, next) => {
    // do someting
});

      这三个参数 to 、from 、next 分别的作用:

        to: Route,代表要进入的目标,它是一个路由对象

        from: Route,代表当前正要离开的路由,同样也是一个路由对象

        next: Function,这是一个必须需要调用的方法,而具体的执行效果则依赖 next 方法调用的参数

          next():进入管道中的下一个钩子,如果全部的钩子执行完了,则导航的状态就是 confirmed(确认的)
          next(false):这代表中断掉当前的导航,即 to 代表的路由对象不会进入,被中断,此时该表 URL 地址会被重置到 from 路由对应的地址
          next(‘/’) 和 next({path: ‘/’}):在中断掉当前导航的同时,跳转到一个不同的地址
          next(error):如果传入参数是一个 Error 实例,那么导航被终止的同时会将错误传递给 router.onError() 注册过的回调
      全局后置钩子:

router.afterEach((to, from) => {
    // do someting
});

        不同于前置守卫,后置钩子并没有 next 函数,也不会改变导航本身

    2. 路由独享的钩子

      单个路由独享的导航钩子,它是在路由配置上直接进行定义的:

cont router = new VueRouter({
    routes: [
        {
            path: '/file',
            component: File,
            beforeEnter: (to, from ,next) => {
                // do someting
            }
        }
    ]
});

    3.组件内的导航钩子

      组件内的导航钩子主要有这三种:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。他们是直接在路由组件内部直接进行定义的:

const File = {
    template: `<div>This is file</div>`,
    beforeRouteEnter(to, from, next) {
        // do someting
        // 在渲染该组件的对应路由被 confirm 前调用
    },
    beforeRouteUpdate(to, from, next) {
        // do someting
        // 在当前路由改变,但是依然渲染该组件是调用
    },
    beforeRouteLeave(to, from ,next) {
        // do someting
        // 导航离开该组件的对应路由时被调用
    }
}

       beforeRouteEnter 不能获取组件实例 this,因为当守卫执行前,组件实例被没有被创建出来,剩下两个钩子则可以正常获取组件实例 this

       可以通过给 next 传入一个回调来访问组件实例。在导航被确认是,会执行这个回调,这时就可以访问组件实例了

beforeRouteEnter(to, from, next) {
    next (vm => {
        // 这里通过 vm 来访问组件实例解决了没有 this 的问题
    })
}

        仅仅是 beforRouteEnter 支持给 next 传递回调,其他两个并不支持。因为归根结底,支持回调是为了解决 this 问题,而其他两个钩子的 this 可以正确访问到组件实例,所有没有必要使用回调、

    4.完整的导航解析流程

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

4.vue-router中的hash模式、history模式、abstract模式

    1.哈希模式(hash mode)

      这是开发中的默认模式,在url中永远带着#号,在浏览器方面其支持度极佳,甚至兼容低版本的ie浏览器。

          即#是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中,不包含#。

          每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置。

      前端路由的原理:window是可以监听到哈希值的变化的(onhashchage事件),这就意味着:当url中的哈希值发生了变化,无需发起http请求,window也可以监听到这种变化,并按需加载前端的代码块。

      哈希模式也是当下单页面应用的标配,所谓前端路由的强大之处也就在这里:路由分发不需要服务器来做,前端自己就可以完成。

    2.历史模式(history mode)

      在url中不带#号,用的是传统的路由分发模式,即当用户输入一个url时,是由服务器在接受用户的这个输入请求,并由服务器解析url的路径然后做相应逻辑处理。

      如果要做到改变url但又不刷新页面的潮流效果,就需要前端用上pushState和replaceState两个H5的api,来把url替换的同时又不刷新页面,但需要后端人员去配置url重定向的问题,不然在访问二级页面时,做刷新操作会报404的错误。这和哈希天生就不会刷新页面的特性不同,历史模式来做这件事属于一种“障眼法”,或者说是“老技术干新活”,又废又麻烦。

      hash模式下:xxx.com/#/id=5 请求地址为 xxx.com,没有问题。
      history模式下:xxx.com/id=5 请求地址为 xxx.com/id=5,如果后端没有对应的路由处理,就会返回404错误

      需要后台配置支持:

      在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

    3.abstract模式

      abstract模式是使用一个不依赖于浏览器的浏览历史虚拟管理后端。
      根据平台差异可以看出,在 Weex 环境中只支持使用 abstract 模式。 不过,vue-router 自身会对环境做校验,如果发现没有浏览器的 API,vue-router 会自动强制进入 abstract 模式,所以 在使用 vue-router 时只要不写 mode 配置即可,默认会在浏览器环境中使用 hash 模式,在移动端原生环境中使用 abstract 模式。 

posted @ 2020-11-06 15:34  Judicious  阅读(1393)  评论(0编辑  收藏  举报