前端路由的优缺点?
优点:传统的后端路由,访问新页面的时候需要向服务端发送新的请求,页面等待响应完成,这个过程有网络延迟。使用前端路由,在变换了路径的同时实现了无请求页面刷新。提高用户体验,同时用户在复制 url
后可以分享页面。
缺点:使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存。
hash和history路由的区别?
-
history
利用了html5
中新增的pushState
和replaceState
方法。这两个方法应用于浏览器记录栈,在当前已有的back、forward、go
基础之上,它们提供了对历史记录 修改的功能(pushState
将传入url
直接压入历史记录栈,replaceState
将传入url替换当前历史记录栈)。 -
histroy
路由不会显示#,匹配的路径会全部传递给服务端。如果服务端并没有响应路由的路径,这个时候需要后端配合解决刷新404
的问题。 -
hash
(url
中#
后面的部分)虽然出现在URL
中,但不会被包含在http
请求中,对后端完全没有影响,因此改变hash
不会重新加载页面,。 -
当
hash
改变时,会触发hashchange
事件,监听该事件,对页面进行更新。
如何实现一个hash路由?
<div>
<ul>
<li><a href="#/home">首页</a></li>
<li><a href="#/user">用户中心</a></li>
<li><a href="#/login">登陆</a></li>
</ul>
<div id="view"></div>
</div>
<script>
// 声明一个view
let view = null;
// 当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完全加载。
window.addEventListener("DOMContentLoaded", onload);
// 监听hash的变化 hashchange用于监听hash值的变化
window.addEventListener("hashchange", setViewChange);
function onload() {
view = document.getElementById('view')
// 一开始进入页面匹配路由
setViewChange();
}
function setViewChange() {
if (!this.location.hash) { //初始化路由
view.innerHTML = "首页";
}
switch (this.location.hash) {
case "#/home":
view.innerHTML = "首页";
break;
case "#/user":
view.innerHTML = "用户中心";
break;
case "#/login":
view.innerHTML = "登陆";
break;
}
}
</script>
解释:location
是 javascript
里边管理地址栏的内置对象,而 location.hash
则可以用来获取或设置页面的标签值。比如 http://domain/#admin的location.hash="#admin"
。 可以根据 location.hash
的不同匹配不同的页面展示。服务端只会解析 #
之前的路径,#
之后的路径 hash
会匹配解析。
pushState和replaceState的区别是?
当我们每一次调用 pushState
的时候,浏览器的历史栈中就会存入当前的状态对象,当去操作浏览器的前进和后退的时候就会更新浏览器的路由。并且触发 popstate
事件。(注意:history.pushState()
或 history.replaceState()
调用的时候不会触发 popstate
事件。)pushState
会增加一条新的历史记录,而 replaceState
则会替换当前的历史记录,replaceState
的用法和 pushstate
的一样。
history.pushState的用法?
history.pushState
方法接受三个参数,依次为:
state
:一个与指定网址相关的状态对象,popstate
事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。可用它来传一些数据
title
:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
url
:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
如何实现一个history路由?
<ul>
<li><a href="?x=home" onclick="changeUl('home');return false">首页</a></li>
<li><a href="?x=user" onclick="changeUl('user');return false">用户中心</a></li>
<li><a href="?x=login" onclick="changeUl('login');return false">登陆</a></li>
</ul>
<div id="view">
<script>
const view = document.getElementById('view')
function changeUl(val) {
let state = val
//每一次执行pushState都会在浏览器的地址栏中增加新的网址
history.pushState(state, null, '?x=' + val);
setViewChange(val)
}
// 设置需要展示的页面
function setViewChange(val) {
if (!val) { //初始化路由
val = 'home'
}
switch (val) {
case 'home':
view.innerHTML = '首页'
break
case 'user':
view.innerHTML = '用户中心'
break
case 'login':
view.innerHTML = '登陆'
break
}
}
window.addEventListener('DOMContentLoaded', onload)
function onload() {
// 一开始进入页面匹配路由
setViewChange()
}
// popstate是浏览器某些行为下触发的事件。
window.addEventListener('popstate', function (e) {
// console.log(e);
setViewChange(e.state)
});
// 与popstate用法相同
// onpopstate = function (event) {
// console.log(event);
// }
</script>
解释:每次 pushState
方法执行的时候都会向地址栏中添加新的历史纪录,同时浏览器的地址栏会显示新的地址,这样就实现了展示内容和地址的统一,当我们操作浏览器前进和后退的时候需要监听 popstate
中的state去设置当前展示的页面。
什么是popstate?
官方解释:每当激活同一文档中不同的历史记录条目时,popstate
事件就会在对应的 window
对象上触发。如果当前处于激活状态的历史记录条目是由 history.pushState()
方法创建的或者是由 history.replaceState()
方法修改的,则 popstate
事件的 state
属性包含了这个历史记录条目的 state
对象的一个拷贝。
简单来说:popstate
中存在浏览器历史记录栈中所有历史纪录,同时 popstate
是浏览器的行为才能触发,这样当我们需要操作浏览器前进后后退时,通过监听 popstate
可以实现页面的更新。(前提是在 pushState
时传入了 state
状态)