1. 认识前端路由和后端路由
前端路由相对于后端路由而言的, 在理解前端路由之前先对于路由有一个基本的了解
路由: 简而言之,就是把信息从原地址传输到目的地的活动
对于我们来说路由就是: 根据不同的url
地址展示不同的页面内容
1.1 后端路由
以前咱们接触比较多的后端路由,当改变url地址时,浏览器会向服务器发送请求,服务器根据这个url,返回不同的资源内容
后端路由的特点就是
- 前端每次跳转到不同url地址,都会重新访问服务器,
- 服务器根据前端的路由,返回不同的数据,或者是HTML页面
1.2 前端路由
前端路由是指通过一定的技术手段,在跳转路由时不在向服务器发送请求, 而在在浏览器端进行处理,
通过不同的url映射到页面不同的DOM元素,不同的url显示不同的页面内容
也就是说
后端路由是url地址映射到服务器上的某些资源
前端路由是url地址映射到浏览器上的某些资源
1.3 什么时候使用到前端路由?
在我们开发单页面应用的时候,会常使用到前端路由
那么什么是单页面应用?
单页面应用的说明
- 以前后端路由不同的url地址会返回不同的HTML页面,也就是说整个项目不止一个HTML页面
- 单页面是指整个项目只有一个页面, 页面显示的内容被抽离为一个一个小的组件
- 通过前端路由,让url地址的改变来映射到不同的组件, 通过url的改变来决定组件的显示与否
1.4 单页面开发的优缺点
优点: 用户体验好
说明
- 单页面只有一个页面,在第一次加载时,就已经将所有资源从服务下载
- 在通过前端路由切换页面时,不是像服务器发送的请求,我们只是通过url决定哪些资源显示
- 因为不用向服务器发送请求,所以请求/响应造成的等待时间就会大大减少,提高了响应速度.
缺点:
不利于SEO优化(单页面应用,只有一个页面会被百度收录,其他的页面都是虚拟的)
使用浏览器的前进后退键的时候会重新发请求,没有合理的利用缓存
单页面无法记住之前滚动条的位置,无法在前进,后退的时候记住滚动的位置
2. 认识前端渲染和后端渲染
在理解前端渲染和后端渲染之前,先理解什么是渲染,渲染什么.
渲染就是将数据和HTML模板组合成为一个完整的能让浏览器显示说有信息内容的页面
2.1 后端渲染
后端渲染也常被称作为服务端的渲染
服务的渲染的说明:
- 当用户发送一个url请求是,服务器会根据路由获取对应的模板和数据,
- 然后服务器会将数据和模板组合成为一个完整的html页面发送给前端
- 浏览器获取的是一个完整的HTML页面,这就是服务的渲染
服务端渲染的好处:
- 前端资源消耗少, 所有的数据和模板组合是在后端完成的,因此不占用客户端的运算资源(模板解析)
- 首屏加载时间快,因为浏览器获取的就是一个完整的页面,因此获取后浏览器直接可以渲染视图
- SEO优化好, 因为SEO蜘蛛在获取页面内容的时候是一个完整的页面内容,可以更好的分析页面内容
服务端渲染的坏处:
- 占用太多服务器 资源
2.2 前端渲染
前端渲染也常被称为客户端渲染
前端渲染说明:
- 前端渲染是指浏览器将页面模板和数据进行组合形成最终的HTML页面
- 原理就是浏览器通过url获取服务器页面模板,服务器并不需要消化太多资源,直接将页面模板发送给前端
- 浏览器拿到页面也后,在解析页面是,通过页面中的ajax向后端请求数据
- 服务器根据前端对于数据的请求,返回给前端数据
- 浏览器拿到数据以后在和页面模板整合,形成最终的页面.
前端渲染的好处:
- 网络传输数据量小,因为一个完整的页面是通过两次请求获取的
- 模板在前端,因此可以通过请求不同的数据改变页面显示结果,
- 进而减少后端渲染时,每次请求都会返回模板解析后的结果
- 不占用服务器资源
前端渲染的坏处:
- 前端资源消耗较多,因为模板的解析和数据的处理都是需要前端处理
- 对于SEO优化不是特别的友好, 因为搜索引擎蜘蛛获取的是页面模板,没法分析页面全部内容
3. 前端路由实现的技术
现在对于前端路由的原理有了一定的了解,那么通过什么技术才能达到,在改变url地址是,浏览器不会向服务发送请求呢?
3.1 基于hash实现的前端路由
其实在学习HTML,CSS阶段,就已经接触并使用hash来处理页面锚点链接.
因此通过hash的改变,url不会向服务器发送请求,这就是用来前端路由的一种技术手段
hash的说明:
- hash就是完整的url地址#后面的内容
- Web 服务不会解析 hash,因为hash 仅仅是客户端的一个状态
- 反而前端就可以在
JavaScript
中通过window.location.hash
来读取到 - 前端在读取到hash以后,就可以通过hash所代表的不同路径处理页面不同的显示逻辑
hash的特点
- hash 能兼容低版本的浏览器
- hash值的改变,不会向服务器发送请求,hash改变的值,只会在浏览器的访问历史中增加记录
- 因此可以通过浏览器的前进,后推按钮切换hash
hash演示示例:
因为每一次hash值发生变化都会触发window.onhashchange
事件,因此可以利用hash处理前端路由
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin:0;
}
li{
list-style:none;
}
ul{
display: flex;
position: fixed;
bottom: 0;
left: 0;
right:0;
height:60px;
border-top:1px solid #999;
}
li{
flex:1;
background: #eee;
border-right:1px solid #999;
}
a{
display:block;
line-height:60px;
text-align: center;
font-size:20px;
text-decoration: none;
}
.content{
position: fixed;
top:0;
left:0;
right:0;
bottom:61px;
background: skyblue;
color:#fff;
text-align:center;
font-size:40px;
line-height: 80px;
}
.box{
display:none;
}
.show{
display:block;
}
</style>
</head>
<body>
<ul>
<li>
<a href="#/">首页</a>
</li>
<li>
<a href="#/list">列表</a>
</li>
<li>
<a href="#/about">关于作者</a>
</li>
</ul>
<div class="content">
<div id="home" class="show">首页</div>
<div id="list" class="box">列表页</div>
<div id="about" class="box">关于作者</div>
</div>
<script>
window.onhashchange = function(){
let path = window.location.hash.slice(1)
// console.log(path );
switch(path){
case "/":
home.className = "show";
list.className = "box"
about.className = "box"
break;
case "/list":
home.className = "box";
list.className = "show"
about.className = "box"
break;
case "/about":
home.className = "box";
list.className = "box"
about.className = "show"
break;
}
}
</script>
</body>
</html>
示例过于简单,请不要在意,重点关注,利用hash,咱们实现了路由的跳转,但是页面没有任何刷新.
这就是前端路由的精髓
3.2 基于HTML新增的history API实现前端路由
HTML新增了history API,来操作路浏览器的历史,因为浏览器窗口会提供一个history对象,用来保存用户操作的历史,
history说明:
- 因为浏览器窗口提供了history来保存历史操作的url,
- 因此使用前进后退按键时,url地址会发生变化,但不会向服务器发送请求
- 但是history里保存的历史记录都是你访问过的路由,
- 那么我们只需要通过一定的API,将一些url路由添加到history历史记录中就可以实现不发送请求的路由跳转
- 因此需要借助于操作history的API
history API
- history.pushState: 向history对象中添加一条历史记录
- history.replaceState: 替换掉当前的history记录
- 两个方法都接受三个参数, 分别为state, title, url
pushState和replaceState 参数
- state用来存放将要插入的history实体的相关信息,它是一个json格式的参数;
- title就是传入history实体的标题
- url用来传递新的history实体的相对路径
history提供的这两个方法不会主动触发浏览器页面的刷新,只是history对象包括地址栏的内容会发生改变,当出发前进后退等history事件时才会进行相应的响应。
history 实现前端路由示例:
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
padding: 0;
margin:0;
}
li{
list-style:none;
}
ul{
display: flex;
position: fixed;
bottom: 0;
left: 0;
right:0;
height:60px;
border-top:1px solid #999;
}
li{
flex:1;
background: #eee;
border-right:1px solid #999;
}
a{
display:block;
line-height:60px;
text-align: center;
font-size:20px;
text-decoration: none;
}
.content{
position: fixed;
top:0;
left:0;
right:0;
bottom:61px;
background: skyblue;
color:#fff;
text-align:center;
font-size:40px;
line-height: 80px;
}
.box{
display:none;
}
.show{
display:block;
}
</style>
</head>
<body>
<ul>
<li>
<a id="homelink">首页</a>
</li>
<li>
<a id="listlink">列表</a>
</li>
<li>
<a id="aboutlink">关于作者</a>
</li>
</ul>
<div class="content">
<div id="home" class="show">首页</div>
<div id="list" class="box">列表页</div>
<div id="about" class="box">关于作者</div>
</div>
<script>
homelink.onclick = function(){
history.replaceState({},"home","/home")
home.className = "show";
list.className = "box"
about.className = "box"
}
listlink.onclick = function(){
history.replaceState({},"list","/list")
home.className = "box";
list.className = "show"
about.className = "box"
}
aboutlink.onclick = function(){
history.replaceState({},"about","/about")
home.className = "box";
list.className = "box"
about.className = "show"
}
</script>
</body>
</html>
示例图:
同样的,我们会发现页面的路径虽然发生改变,但是浏览器并未向服务器发送请求,也没有刷新页面.
当然了,这里提及前端路由,是想让大家理解前端路由的概念和实现的技术.
Vue的路由也是基于这些技术实现的, 当然了Vue路由一定是经过封装处理的,
之后我们就要看看研究研究Vue的路由了