参考资料
- 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 {// 模拟从后台获取到的菜单栏以及其urlstatic 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']]);// 获取本页面不含参数的urlstatic 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=homeloadPage();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中。