共计 1799 个字符,预计需要花费 5 分钟才能阅读完成。
- 项目需求:需要在原 MVC 项目上实现单页面多 tab 切换,局部刷新功能。
- 痛点:原 MVC 项目菜单栏使用的是 a 标签,利用 a 标签的 hare 属性跳转到对应界面,所以导致每个界面都得重新加载一遍;项目早已上线 正常运转,大改框架代价比较大,只得另辟蹊径。
- 思路:通过点击菜单,动态增加 Iframe, 利用 Iframe 的 src 属性,将子页面与母板页结合,再通过控制 Iframe 的显隐,实现界面的切换,另外利用 history 增加路由管理功能。
- 原 MVC 项目上效果实现后,自己花时间整理了一版 Html+Jq 实现的例子,并整理出有关 Iframe 和 history 路由的有关知识点,还有一些实现过程中遇到的小坑,供大家参考!
- 废话少说,先上效果图
源码连接(有详细注释,可根据实际需求修改,万变不离其中):https://github.com/xuqiaoba/Iframe-tab-router
关于 history 方法,网上已经有很多解释了,本文 Demo 中主要使用了
window.history.pushState(state, title, url);
- state:一个与指定网址相关的状态对象,popstate 事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填 null。可用它来传一些数据
- title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填 null。
- url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
// 监听浏览器前进后退事件
window.addEventListener("popstate", function (e) {console.log(e)
});
浏览器的前进后退功能实现后,当时就试着全局刷新了一下,结果。。。
这很正常,浏览器地址栏里面不就是指向的这个子界面嘛。
所以我就想到了监听“浏览器重新加载”事件
// 监听重新加载界面事件
window.onload = function (e) {window.history.pushState({ id: 1, url: './Home.html', menuname: '主界面'}, "title", './Home.html');
window.location.reload()}
最初我将监听“浏览器重新加载”事件写在了母板页中,本来想着是,刷新界面,让他回到“最初的摸样”,先改变浏览器当前路由为“Home.html”,让后刷新当前界面,结果,路由有那么一瞬间是改变了,但紧接着又变回子界面路由地址了,且界面显示的还是子界面。
当时有点懵了,不知道咋回事,百度一番,发现父界面刷新,其子界面也会被刷新,也就是说路由变的一瞬间是父级界面刷新了,但其子界面紧接着也跟着刷新了,所以路由马上就改变成了 Iframe 里面的 src 地址。
这是我就想着将“监听重新加载界面事件”写到每个子界面中去,这下思路应该正确了吧。结果。。。
被“无限嵌套”了。这也正常,既然 子界面的 src 被重定向成“Home.html” 了,自然每个子界面都跟母板页长得一样了呀。
再冷静分析一波,需要判断当前刷新的界面是母板页还是子界面,如果是母板页,则执行 window.history.pushState({id: 1, url:'./Home.html', menuname: '主界面'}, "title", './Home.html'); window.location.reload()
,如果是子界面,则直接跳过。
这里就用到了 window.parent.father() 方法,通过 window.parent 可以调用到父级界面定义的方法 ”father()”, 如果在父级界面调用 window.parent.father() 则会抛出异常。这里就巧妙的运用 try…catch…,完美解决这个问题。
// 监听重新加载界面事件 (点击浏览器按钮刷新,会进 catch,点击菜单刷新,正常调用 fj())
window.onload = function (e) {
try {window.parent.father()
} catch (e) {window.history.pushState({ id: 1, url: './Home.html', menuname: '主界面'}, "title", './Home.html');
window.location.reload()}
}
欢迎交流,欢迎 Star (^_^)
经验总结,代码加工厂!