作者:TYANer
单页应用对于大家而言,可能是一个比较陌生的概念,但是其实大家都和单页应用打过交道。之所以这么说,是因为目前平台开发的所有中台系统的前端部分,包括Kadmin、TGS、OTA都属于单页应用。那么,到底什么是单页应用呢?
单页应用,顾名思义,就是整个应用只有一个主页面,其余的“页面”,实际上是一个个的“组件”。单页应用中的“页面跳转”,实际上是组件的切换,在这个过程中,只会更新局部资源,页面不会整个刷新。也正是因为这个原因,当我们的前端代码有更改,重新部署之后,如果用户不主动刷新,就会发现有“资源缓存”。
以TGS为例,下面每一步操作,都会清除请求日志,重新记录。
1.通过地址栏输入地址进入页面。此时,会请求主页面https://console.tgs-dev.tap4fun.com/
和公共的资源文件。
2.点击跳转到登录板块。可以看到,由于初次进入应用的时候,已经加载了所有的静态资源,在“页面切换”时,只发送了相关的API请求。
3.再次刷新后,重新请求了静态资源。
单页应用的实现
单页应用的实现主要有两种方式,hash模式和history模式。从表现上来说,history模式和hash模式都能够实现不刷新的URL跳转。在平台的业务中,Kadmin采用的是history模式的路由跳转,TGS采用的是hash模式的路由跳转。
Kadmin URL参考:https://kadmin-inner.tap4fun.com/deploy/application/list/
TGS URL参考:https://console.tgs-dev.tap4fun.com/#/pay/goods
1、history模式
history模式是基于HTML5规范,利用history.pushState
、history.replaceState
API来完成 URL 跳转而无须重新加载页面。
API简介:
(1)history.pushState()
history.pushState(stateObj, title, url)
- stateObj:状态对象,存储 JSON 字符串,可以用在 popstate 事件中。
- title:标题,现在大多浏览器忽略这个参数,直接用 null 代替。
- url:任意有效的URL,必须与当前页面处在同一个域,用于更新浏览器的地址栏。
history.pushState()用于新增一个历史记录。
(2)history.replaceState()
history.replaceState(stateObj, title, url)
history.replaceState()
的使用与history.pushState()
非常相似,区别在于replaceState()
是修改了当前的历史记录项而不是新建一个。
history API详细介绍:https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API#Adding_and_modifying_history_entries
history模式的具体实现在不同的框架中可能不尽相同,但是实现原理基本都是通过监听触发history对象修改的事件,并绑定相应的处理函数。
2、hash模式
hash模式使用 URL 的 hash 来模拟一个完整的 URL。由于hash本来的作用是锚点,因此,在 URL 改变时,页面不会重新加载。所以hash模式需要监听hashchange事件,并绑定相关的“页面切换”处理函数,以实现“页面切换”。同时可以使用 window.location.hash 属性获取和设置 hash 值。
window.addEventListener('hashchange', updateView(), false);
使用hash模式的单页应用,URL中会有一个“#”,让它和真正的URL始终有一些差异,不少开发者会觉得这样的形式有些“丑陋”,因此更偏爱于history模式。
单页应用的优点
- 局部刷新,渲染速度快。
- 允许浏览器在后台向服务器发出请求以完全获取其他内容或新“页面”的同时,保持当前页面的打开状态,交互性好。
- “页面”间数据传递十分方便,可以使用全局变量。
- 公共资源只需要加载一次,减少了HTTP请求数。
- 组件可复用。
单页应用的缺点
- 静态资源更新后,不会因为“页面切换”重新加载,必须手动刷新,否则可能出错。
- 在首页可能加载不必要的资源,当初次加载文件过多时,需要做相关的调优。否则,资源间的下载和执行相互阻塞,会导致页面初次加载速度变慢。
- 单页应用不利于SEO。