前端路由

为什么要有前端路由

  • 传统的多页面形式
    刚开始,我们要实现路由的跳转都是依靠后端路由实现的。每一个页面都是一个单独的html文件,用户进行页面切换的时候,浏览器发送不同的url请求,服务器接收到以后把该url对应的html文件返回给我们。浏览器拿到之后就开始解析,显示。
    缺点:

    • 每一次跳转都需要去向后端请求完整的html页面,重新加载。
    • 加大服务器的压力
  • SPA
    随着ajax(浏览器实现异步加载的一种技术方案)的出现,单页面模式逐渐代替了传统模式。通俗一点解释,就是我们现在只有一个html文件。多个页面的切换实际上是视图的切换。SPA是通过JS来修改html内容。其自身的url是没有改变的。单页应用不仅在页面交互是无刷新的,连页面跳转都是无刷新的,为了配合实现单页面应用跳转,前端路由孕育而生。
    缺点:

    • 对于前进后退等操作,不能达到想要的效果,因为页面的Url并没有改变
    • SPA 中虽然由于业务的不同会有多种页面展示形式,但只有一个 url,对 SEO 不友好,不方便搜索引擎进行收录。
  • 前端路由的诞生

    • 总结一下前端路由需要解决的问题:
      保证只要一个HTML页面,页面在不完全刷新的情况下切换视图,为SPA中的每一个视图匹配一个特殊的url,通过这个url来进行刷新,前进,后退以及SEO等操作。也就是说url变了,但是并没有重新加载。
    • 总结一下实现的关键:

      • 改变url且不发送请求
      • 监听到url的变化
        缺点:由于服务器没有保留完整的 HTML,通过 js 进行动态 DOM 拼接,需要耗费额外的时间,不如服务端渲染速度快。

前端路由的实现

其实路由简单来说,就是我们url和我们视图的一个映射,这个映射是单向的,通过监听到url的变化,来改变我们的视图。
前端路由主要有两种方式:

1. Hash

  • 什么是hash

https://juejin.cn/post/684490...
后面的heading-0就是我们的锚,也就是hash。hash也叫锚点,主要用于页面定位。与hash值对应的dom id的页面会出现在可视区。
(一个完整的 URL 包括:协议、域名、端口、虚拟目录、文件名、参数、锚。)

- hash值更新的特点
    - hash值更新,会改变url,但是http请求的时候不包含锚定位,所以对后端无影响。
    - 因为不包含锚定位,所以hash值改变的时候,不会触发页面的重新加载。
    - hash值的更改,会改变浏览器的历史记录,并且可以通过window.onhashchange()事件监听我们的hash变换。

这满足我们上面的实现关键的两个。所以我们是通过改变hash值来进行页面的跳转的。那我们应该怎么去改变呢?

改变url的hash值的三种方式:
  - a标签跳转
  - 设置window.location.hash
  - 浏览器前进键(history.forword())、后退键(history.back())

总结:这三种改变hash值的方式,会改变我们的url,并且会改变浏览器的历史记录,可以通过window.onhashchange()事件监听。但是因为http请求不会带hash值,所以对后端无影响,也不会触发页面的重新加载。所以 hash 模式路由就是利用 hashchange 事件监听 URL 的变化,从而进行 DOM 操作来模拟页面跳转。

2. History

  • 在 HTML5 之前,浏览器就已经有了 history 对象。但在早期的 history 中只能用于多页面的跳转,后面由于SPA的广泛应用,HTML5提供了两个新的API。 history.pushState() 和 history.replaceState()
  • 由于 history.pushState() 和 history.replaceState() 可以改变 url 同时,不会刷新页面,所以在 HTML5 中的 histroy 具备了实现前端路由的能力。

Hash和history的对比

hash的优点:

  • hash的兼容性更好,可以兼容到IE8
    hash的缺点:
  • 形式比较丑
  • 相同 hash 值不会触发动作将记录加入到历史栈中,而 pushState 则可以

vue router 以及 react router对比

其实这两个主流框架,核心都是借助浏览器自有的特性。

1. router对象类型

- vue 把 VueRouter作为一个对象
- React 把router作为一个组件。

react-router 的注入方式是在组件树顶层放一个 Router 组件,然后在组件树中散落着很多 Route 组件,顶层的 Router 组件负责分析监听 URL 的变化,在其下面的 Route 组件渲染对应的组件。在完整的单页面项目中,使用 Router 组件将根组件包裹,就能完成保证正常的路由跳转。
2. 基础组件

- Vue-router
  • <router-view> 组件的渲染
  • <router-link> 直接跳转
    Rect-router-dom (react-router-dom在react-router的基础上扩展了可操作dom的api。)
  • <BrowserRouter/>、<HashRouter/> 区分选择的路由方式。history还是hash
  • <link> 点击跳转,和<router-link>类似,<router>和<router-view>类似,组件的渲染。
  • <Switch/> 用来将 react-router 由包容性路由转换为排他性路由,每次只要匹配成功就不会继续向下匹配。vue-router 属于排他性路由。

3. 路由模式
vue-router和react-router-dom都有两种路由模式,history和hash。但是在实现和使用上有些许区别。不过底层都是依靠浏览器的自有特性。
Vue-router:

  • 两种模式在实例化Vue-router的时候通过配置路由选项mode来决定。
  • hash模式
    首先判断浏览器是否支持pushState,如果支持,就通过pushState来改变hash值。popstate 监听浏览器操作,完成导航功能。如果不支持,通过设置window.location.hash,hashchange 监听 URL 变化完成路由导航。
  • History模式
    地址栏 URL 中没有 #。与 Hash 模式实现导航的思路是一样的。不同的是,vue-router 提供了 fallback 配置,当浏览器不支持 history.pushState 控制路由是否应该回退到 hash 模式。默认值为 true。

React-router-dom:

  • 实现依赖 history.js,history.js 是 JavaScript 库。<BrowserRouter> 、 <HashHistory> 分别基于 history.js 的 BrowserHistory 类、HashHistory 类实现。
  • Hash模式

    • HashHistory 类直接通过 location.hash、location.replace 和 hashchange 实现,没有优先使用 history 新特性的处理。
  • History模式

    • BrowserHistory 类通过 pushState、replaceState 和 popstate 实现,但并没有类似 vue-router 的兼容处理

参考文献:
https://jelly.jd.com/article/...

03-05 20:06