前端路由:原理篇


通过这篇文章,你可以了解到

  • 为什么需要前端路由?解决了什么问题?
  • 前端路由的基本原理是什么?
  • hash路由的hash值会发送到服务端吗?
  • history路由为什么需要服务端支持?
  • hash和history两种模式怎么选?

如果这些你都了解,可以看我另一篇博客:前端路由:实现篇_Palate的博客-CSDN博客

一、为什么需要前端路由

1. 什么是前端路由
  • 前端路由,就是一个前端不同页面的状态管理器,可以不向后台发送请求而直接通过前端技术实现多个页面的效果。
2. 单页面应用的问题
  • 最开始的网页是多页面的,后来出现了 Ajax 之后,才慢慢有了 SPASPA应用指的是应用只有一个主页面,通过动态替换DOM内容并同步修改url地址,来模拟多页应用的效果,切换页面的功能直接由前台脚本来完成,而不是由后端渲染完毕后前端只负责显示。
  • AJAX局部刷新,导致浏览器的URL不会发生任何变化而完成了请求,从而破坏了用户浏览体验。同时本次浏览的页面内容在用户下次使用URL访问时将无法重新呈现,使用路由可以很好地解决这个问题。
3. 前端路由的作用

前端路由,解决SPA 的两个弊端:

  1. 用户在使用的过程中,url 不会发生任何改变。当用户操作了几步之后,一不小心刷新了页面,又会回到最开始的状态。
  2. 由于缺乏 url,不方便搜索引擎进行收录。
3. 两种实现方式
  • 在单页面web网页中, 有两种实现方式

    • hash模式:修改 URLhash 值,触发 hashchange 事件去渲染不同的内容,
    • history模式:利用history API实现``URL地址改变,触发popstate事件渲染不同的内容
  • 共同点

    • 提供改变了url的方法,不刷新页面
    • 监听url变化,加载相应内容

二、hash模式

1. 原理

​ 使用window.location.hash属性及窗口的onhashchange事件,可以实现监听浏览器地址hash值变化,执行加载相应的内容。

2. 理解要点
  1. 什么是hash值

    hash指的是地址中#号以及后面的字符,也称为散列值。hash也称作锚点,本身是用来做页面跳转定位的。如http://localhost/index.html#abc,这里的#abc就是hash;

  2. hash值不会发送到服务器

    hash值是不会随请求发送到服务器端的,所以改变hash,不会重新加载页面;

  3. 监听 hashchange 事件

    监听 window 的 hashchange 事件,当散列值改变时,可以通过 location.hash 来获取和设置hash值;

  4. hash值变化反应到地址栏

    location.hash值的变化会直接反应到浏览器地址栏;

3. 触发hash.change事件的几种情况
  1. 触发hash值变化

    浏览器地址栏散列值的变化(包括浏览器的前进、后退)会触发window.location.hash值的变化,从而触发onhashchange事件;

  2. 输入整个url

    当浏览器地址栏中URL包含哈希如 http://www.baidu.com/#home,这时按下输入,浏览器发送http://www.baidu.com/请求至服务器,请求完毕之后设置散列值为#home,进而触发onhashchange事件;

  3. 输入hash部分

    当只改变浏览器地址栏URL的哈希部分,这时按下回车,浏览器不会发送任何请求至服务器,这时发生的只是设置散列值新修改的哈希值,并触发onhashchange事件;

  4. 点击 a 标签

    html中<a>标签的属性 href 可以设置为页面的元素ID如 #top,当点击该链接时页面跳转至该id元素所在区域,同时浏览器自动设置 window.location.hash 属性,地址栏中的哈希值也会发生改变,并触发onhashchange事件;

// 设置 url 的 hash,会在当前url后加上'#abc'
window.location.hash='abc';
let hash = window.location.hash //'#abc'

window.addEventListener('hashchange',function(){
	// 监听hash变化,点击浏览器的前进后退会触发
})

三、history 模式

1. 原理
  • history 对象保存了当前窗口访问过的所有页面网址。history 对象发生改变时,只会改变页面的路径,不会刷新页面。
  • 每当 history 对象出现变化时,就会触发 popstate事件。
2. 理解要点
  1. History 对象

    HTML5History API为浏览器的全局history对象增加的扩展方法。一般用来解决ajax请求无法通过回退按钮回到请求前状态的问题History 对象保存了当前窗口访问过的所有页面网址。通过 history.length 可以得出当前窗口一共访问过几个网址。

    由于安全原因,浏览器不允许脚本读取这些地址,但是允许在地址之间导航。

    浏览器工具栏的“前进”和“后退”按钮,其实就是对 History 对象进行操作。

  2. 改变url方法

    history 路由中,我们一定会使用window.history中的方法,常见的操作有:

    • back():后退到上一个路由;
    • forward():前进到下一个路由,如果有的话;
    • go(number):进入到任意一个路由,正数为前进,负数为后退;
    • pushState(obj, title, url):前进到指定的 URL,不刷新页面;
    • replaceState(obj, title, url):用 url 替换当前的,不刷新页面;

    调用这几种方式时,都会只是修改了当前页面的 URL,不会刷新页面。如果有面试官问起这个问题“如何仅修改页面的 URL,而不发送请求”,那么答案就是这 5 种方法。但前 3 个方法只是路由历史记录的前进或者后退,无法跳转到指定的 URL。

    pushStatereplaceStateHTML5 新增的history对象的方法,提供了对历史记录进行修改的功能。页面不会刷新,只是导致 History 对象发生变化,地址栏会有变化。

  3. popstate 事件

    仅仅调用pushState()方法或replaceState()方法 ,并不会触发该事件。那该怎么办?如果我们能罗列出所有可能改变 history 的途径,然后在这些途径一一进行拦截,不也一样相当于监听了 history 的改变吗

    对于一个应用而言,url 的改变只能由以下 3 种途径引起:

    1. 点击浏览器的前进或者后退按钮;
    2. 点击 a 标签;
    3. 在 JS 代码中直接修改路由

    第 2 和第 3 种途径可以看成是一种,因为 a 标签的默认事件可以被禁止,进而调用 JS 方法。关键是第 1 种,HTML5 规范中新增了一个 onpopstate 事件,通过它便可以监听到前进或者后退按钮的点击。

  4. 实现思路

    其实现思路也很简单如下图所示:

img

3. 注意

history 致命的缺点就是当改变页面地址后,强制刷新浏览器时,(如果后端没有做准备的话)会报错,因为刷新是拿当前地址去请求服务器的,如果服务器中没有相应的响应,会出现 404 页面

(hash路由没有这个问题)

四、使用场景

  • 一般场景下,hashhistory 都可以,除非你更在意颜值,# 符号夹杂在 URL 里看起来确实有些不太美丽。
  • 如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用history.pushState API 来完成URL 跳转而无须重新加载页面。不过这种模式要玩好,还需要后台配置支持。
  • 所以呢,要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

五、总结

简介

  • 前端路由,是一个前端不同页面的状态管理器,可以不向后台发送请求而直接通过前端技术实现多个页面的效果。

作用

  • 保存用户页面状态
  • 方便搜索引擎收录

主要介绍两种路由模式:

共同点

  • 改变url地址,不刷新页面
  • 监听url地址变化,加载相应内容

区别

  • hash会在浏览器地址后面增加#号,而history可以自定义地址。
  • hash路由不需要服务端的支持,history需要服务端支持,因为hash值不会发给后端,而history模式修改URL地址后,再进行刷新会使用该地址发送请求。

详细对比

img

参考

单页面应用路由实现原理:以 React-Router 为例 · Issue #109 · youngwind/blog · GitHub
细说前端路由的hash模式和 history模式 - 掘金 (juejin.cn)

  • 4
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值