关于单页应用
单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。简单来说就是用户只需要加载一次页面就可以不再请求,当点击其他子页面时只会有相应的URL改变而不会重新加载。
- 大部分用于: 移动端 / PC端的后台管理系统
单页应用的实现
依赖hash的改变(锚点)
依赖历史记录(history)
- 前端路由:在页面中同一个位置,根据不同的hash值显示不同的页面结构
实现改变URL页面不刷新
按照常规的逻辑我们切换URL好像就会跳转网页,但是转念一想锚链接的URL不是也改变了吗? 这里,存在两种满足需求的方式。
- 利用URL中的hash方式
了解http协议就会知道,url的组成部分有很多,譬如协议、主机名、资源路径、查询字段等等,其中包含一个称之为片段的部分,以“#”为标识。打开控制台,输入 location.hash,你可以得到当前url的hash部分(如果当前url不存在hash则返回空字符串)。接下来,输入 location.hash = '123',会发现浏览器地址栏的url变了,末尾增加了’#123’字段,并且,页面没有被重新刷新。很显然,这很符合我们的要求。- 利用H5的history API
html5引入了一个history对象,包含了一套访问浏览器历史的api,可以通过window.history访问到它。 HTML5 History API包括2个方法:history.pushState()和history.replaceState(),和1个事件:window.onpopstate。这两个方法都是对浏览器的历史栈进行操作,将传递的url和相关数据压栈,并将浏览器地址栏的url替换成传入的url且不刷新页面,而且他们的参数也相同,第一个参数用于存储该url对应的状态对象,该对象可在onpopstate事件中获取,也可在history对象中获取。第二个参数是标题,目前浏览器并未实现。第三个参数则是设定的url。一般设置为相对路径,如果设置为绝对路径时需要保证同源。。不同的是pushState 将指定的url直接压入历史记录栈顶,而 replaceState 是将当前历史记录栈顶替换成传入的数据。不过低版本对history AIP的兼容性不是很好。
监听URL的变化,执行页面替换逻辑
- 对于hash方式,我们通常采用监听hashchange事件,在事件回调中处理相应的页面视图展示等逻辑。
两种实现的比较
总的来说,基于Hash的路由,兼容性更好;基于History API的路由,更加直观和正式。但是,有一点很大的区别是,基于Hash的路由不需要对服务器做改动,基于History API的路由需要对服务器做一些改造。
代码实现
<div id="box">
<div class="top">顶部通栏</div>
<div class="bottom">
<div class="slide">
<a href="#/first">first</a>
<a href="#/second">second</a>
<a href="#/third">third</a>
<a href="#/fourth">fourth</a>
</div>
<div class="content router-view"></div>
</div>
</div>
<style>
*{
margin: 0;
padding: 0;
}
html,body,#box{
width: 100%;
height:100%;
}
#box{
display: flex;
flex-direction:column;
}
#box>.top{
height: 130px;
background: skyblue;
}
#box>.bottom{
flex:1;
display: flex;
}
#box>.bottom>.slide{
width: 230px;
background-color: orange;
box-sizing: border-box;
padding: 15px;
}
#box>.bottom>.slide>a{
font-size: 22px;
display: block;
margin: 10px 0;
text-decoration: none;
color: #333;
}
#box>.bottom>.content{
flex: 1;
box-sizing: border-box;
padding: 15px;
background: purple;
font-size: 100px;
color: white
}
</style>
//1. 准备不同的页面显示结构
const template1 = `
<div>
first
</div>
`;
const template2 = `
<div>
second
</div>
`;
const template3 = `
<div>
third
</div>
`;
const template4 = `
<div>
fourth
</div>
`;
//2. 获取路由入口对象
let routerView = document.querySelector('.router-view');
//3. 捕获浏览器地址栏 hash值的改变
window.onhashchange = function(){
console.log('地址栏hash值改变了');
console.log(window.location.hash);
//获取hash
const {
hash} = window.location;
//判断hash值,进行不同的结构渲染
switch(hash){
case '#/first' : routerView.innerHTML = template1;break;
case '#/second' : routerView.innerHTML = template2;break;
case '#/third' : routerView.innerHTML = template3;break;
case '#/fourth' : routerView.innerHTML = template4;break;
}
}