参考资料
- html5新特性:利用history的pushState等方法来解决使用ajax导致页面后退和前进的问题
- 击按钮切换iframe的src,这个路径如何不会被记录到history中?
- iframe 后退 浏览器history 问题
- ajax与HTML5 history pushState/replaceState实例
目录
- 一. 遇到的问题
- 二. 问题分析
- 三. 代码示例
- 四. 代码分析
- 五. 效果
一. 遇到的问题
我们使用iframe嵌套自己系统的页面,但是浏览器刷新之后,无法保持当前打开的页面
二. 问题分析
⏹原因
之所以会刷新页面后无法保持住当前打开的页面,是因为浏览器地址栏的url始终是固定的,我们打开的页面改变的是iframe
标签的src属性值,从而实现不同页面之间的切换。
⏹解决
在url的后面添加?name=当前画面id,当我们进入页面之后,根据name的参数值,来改变iframe
标签,从而实现刷新后页面保持。
三. 代码示例
⏹登录页面,点击后登录到系统的首页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="login">点击登录系统</button>
</body>
<script>
login.addEventListener("click", function() {
location.replace("./03-2-系统页面.html?name=home");
});
</script>
</html>
⏹主系统页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#contanier {
display: flex;
justify-content: space-between;
}
iframe {
/* 根据视口的宽度和高度计算iframe的宽和高 */
width: calc(100vw - 150px);
height: calc(100vh - 30px);
}
</style>
<title>系统首页</title>
</head>
<body>
<div id="contanier">
<div id="menu">
<li id="es6">ES6网站</li>
<li id="css">css网站</li>
<li id="java">java网站</li>
<li id="php">php网站</li>
</div>
<div id="content">
<iframe></iframe>
</div>
</div>
</body>
<script src="https://code.jquery.com/jquery-3.6.3.js"></script>
<script>
// 页面的工具类
class Utils {
// 模拟从后台获取到的菜单栏以及其url
static urlMap = new Map([
['es6', './03/02-es6.html'],
['css', './03/03-css.html'],
['java', './03/04-java.html'],
['php', './03/05-php.html'],
['home', './03/01-首页.html']
]);
// 获取本页面不含参数的url
static getUrl() {
const {
origin,
pathname
} = location;
return origin + pathname;
}
// 获取url中指定的参数
static getParamFromUrl(url, param) {
return new URLSearchParams(new URL(url).search).get(param);
}
}
$(function() {
// 事件绑定
eventBind();
// 加载页面
loadPage();
});
function eventBind() {
// 当浏览器前进后退时,会触发popstate事件
window.addEventListener("popstate", function(evnet) {
loadPage();
});
$("#menu li").click(function(event, triggerFlg) {
const pageId = this.id;
reloadIframe(pageId);
/*
如果是用户手动点击触发,则将当前url添加到浏览器的history中
如果是通过函数来触发的点击事件,则不将url添加到浏览器的history中
*/
if(!triggerFlg) {
history.pushState(null, "", `${Utils.getUrl()}?name=${pageId}`);
}
});
}
function loadPage() {
const pageId = Utils.getParamFromUrl(location.href, "name");
// 如果url中没有 ?name=对应的属性值,或者Utils.urlMap中没有pageId对应值的话
if(!pageId || !Utils.urlMap.get(pageId)) {
// 将当前 url + ?name=home 的路径替换到浏览器的history中
history.replaceState(null, "", `${Utils.getUrl()}?name=home`);
// 重载页面,此时url中的参数为?name=home
loadPage();
return;
}
// 如果当前是home页的话,就重载iframe标签
if(pageId == "home") {
reloadIframe(pageId);
return;
}
/*
手动触发点击事件
第二个参数是为了在手动触发点击事件的时候传递一个参数
传递此参数的目的是为了让点击事件的回调区分,当前点击事件是用户主动点击触发,
还是通过函数来手动触发的
*/
$("#" + pageId).trigger("click", true);
}
function reloadIframe(pageId) {
// 清空iframe标签
$("#content").empty();
// 创建新的iframe标签,并指定url
$("<iframe>", {
src: Utils.urlMap.get(pageId)
}).appendTo($("#content"));
}
</script>
</html>
四. 代码分析
- 在
reloadIframe
方法中,我们并不是直接修改的iframe标签的src属性,而是销毁掉既存的iframe标签,并新创建一个。如果直接修改src属性的话,src中的地址会直接存入history
对象中,给浏览器前进后退功能带来影响。直接创建iframe标签,src中的地址并不会写入history
对象中。 - 由于新创建的
iframe
标签的src
属性值并不会存入history对象中,因此我们需要手动调用history.pushState()
这个api来存入到history对象中。 $("#menu li")
上的点击事件可由用户主动点击触发,也可由window上的popstate
事件手动触发,当是由popstate事件手动触发时,说明用户使用了浏览器的前进后退功能,此时不需要将url存储history中。