什么是路由👻
当提到路由的时候你会想到什么? 路由器?简单来说,路由就是URL
到函数的映射
路由这个概念最先是后端出现的
- 早期的网站开发的所有页面都是由服务器来进行渲染的,服务器直接生产渲染好的
HTML
页面返回给客户端显示 - 一个页面有自己对应的
URL
,当你输入URL的时候会将这个URL
发送到服务器,服务器通过正则进行匹配处理,最终生成HTML和数据返回给前端 - 以上就是后端路由,简单来说路由就是用来跟后端服务器进行交互的一种方式
- 但是这种方式很糟糕的情况就是整个页面都由后端人员来维护,如果前端人员需要开发页面就要通过修改
JSP
等页面进行修改,这种情况下HTML
页面代码和逻辑会混合在一起,无论是编写还是维护都很糟糕和麻烦 - 于是就出现了前后端分离的阶段
前后端分离🚀
- 随着Ajax的出现,有了前后端分离的开发模式
- 当我们请求数据接口的时候,后端只提供API来返回数据,前端通过Ajax来获取数据并渲染到页面中
- 这样可以很清晰的分配前后端的职责,让前端专心于用户的交互和可视化,让后端专心于数据的处理
SPA(单页Web应用)阶段🍻
- 在传统的网页中,每个HTML文件都是一个完成的HTML页面,每当访问一个URL就要去服务端请求大量的数据,不单单增加了性能损耗还破换了用户浏览体验
- 在
SPA
(单页Web
应用)中,单纯的浏览器地址改变, 利用了JavaScript
动态变换网页内容,网页不会重载 - 简单来说就是在单页面
Web
网页中, 页面的切换就是视图之间的切换 - 其实
SPA
最主要的特点就是在前后端分离基础上加了一层前端路由
前端路由的核心
- 改变
URL
,但是页面不进行整体的刷新 - 而网站与用户交互时不进行整体刷新的同时,可以有局部的内容进行改变
- 前端渲染把渲染的任务交给了浏览器,通过客户端来解决页面的构建,这个很大程度上缓解了服务端的压力。而且配合前端路由,无缝的页面切换体验自然是对用户友好的。
说了这么多,那该如何实现呢?接下来说到的hash
(哈希)模式和history
模式就是前端路由的实现方式
hash模式
hash
是URL
中hash(#)
及后面的那部分,常用作锚点在页面内进行导航,改变URL
中的hash
部分不会引起页面刷新- 浏览器不会对
#
号后面的路径对服务端发起路由请求,也就是说当你请求一个https://juejin.cn/#123
和https://juejin.cn/
其实到服务端都是去请求https://juejin.cn/
这个页面的内容 hash
的改变会通过触发hashchange
事件监听URL
的变化,来渲染对应的页面,通过浏览器前进后退改变URL
、通过标签改变URL
、通过window.location
改变URL
,这几种情况改变URL
都会触发hashchange
事件
常用的API
window.location.hash = '123' // 设置 url 的hash,会在当前url后加上 '#123' let hash = window.location.hash console.log(hash) //#123 window.addEventListener('hashchange', function(){ // 监听hash变化 }) 复制代码
网络异常,图片无法展示
|
history模式
window.history
属性指向history
对象,它表示当前窗口的浏览历史history
对象保存了当前窗口访问过的所有页面网址,通过window.history.length
可以得出当前窗口一共访问过几个网址,通过window.history.state
可以得到History
堆栈最上层的状态值
window.history.length //4 window.history.state //null 复制代码
在history
模式中,URL
不带#
号,那他看起来就和通常的URL
一样了,那该如何改变URL
不引起页面刷新呢?
那么就需要用到在HTML5
的规范中,history
对象新增了的pushState
和replaceState
两个方法, 这两个方法都接受三个参数(state, title, url)
state
:需要保存的数据对象,通过pushState
方法可以将该对象内容传递到新页面中title
:指标题,但一般用不到,没有浏览器可以支持填null
即可url
:设定新的历史记录的url
,必须与当前页面处在同一个域,不指定的话则为当前的路径,如果设置了一个跨域网址,则会报错,这样设计的目的是,防止恶意代码让用户以为他们是在另一个网站上,因为这个方法不会导致页面跳转,url
可以是绝对路径,也可以是相对路径
history.pushState()
- 该方法可以理解为在历史记录添加一条记录
let state={ app:'sth' } window.history.pushState(state, '', '') console.log(window.history.state) //{app:"sth"} console.log(window.history.length)//每执行一次pushState则会改变 复制代码
url
设置了跨域网址则会报错
history.replaceState()
- history.replaceState() 的使用与 history.pushState() 非常相似,区别在于 replaceState() 是修改了当前的历史记录项而不是新建一个。
let state={ app:'sth' } window.history.replaceState(state, '', '') console.log(window.history.state) //{app:"sth"} console.log(window.history.length)//每执行replaceState不会改变 复制代码
由于history.pushState()
和history.replaceState()
可以改变url
同时,不会刷新页面,所以在HTML5
中的histroy
也具备了实现前端路由的能力
两种模式的比较👈
hash | history | |
外观 | 有些许丑 | 比较优雅 |
兼容性 | 兼容性较好,可以兼容IE8 | 兼容性相对较差 |
锚点功能 | 因为是在url加#导致锚点失效 | 有效 |
设置URL | 因为只可修改#后面的hash所以只可设置与当前同文档的 URL | 设置的新 URL 可以是与当前 URL 同源的任意 URL |
刷新限制 | 无需服务端配合 | 需要服务端配合 |
写在最后👋
- 前端路由的核心实现原理理解起来其实很简单,但是结合具体框架后
(vue-router,react-router)
,框架增加了很多特性,如动态路由、路由参数、路由动画等等,这些导致路由实现变的复杂 - 但是只要真正理解了其中遇到问题也就迎刃而解了,在写这篇文章的时候也让我重新巩固梳理了基础,所以只要把学到的东西善于总结起来就会不断扩充自己的大脑
- 如果您觉得这篇文章有帮助到您的的话不妨点赞支持一下哟~~😛