实现流程
在<body>中动态添加<f-body>元素, 只显示(style.display)最上方的一个<f-body>
index.html
<!doctype html>
<html lang="zh-cn">
<head><meta charset="UTF-8" /><title>Awesome Capacitor App</title><meta name="viewport"content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /><meta name="format-detection" content="telephone=no" /><meta name="msapplication-tap-highlight" content="no" /><link rel="icon" type="image/x-icon" href="./assets/icon/favicon.ico" /><link rel="png" type="image/png" href="./assets/imgs/logo.png" /><link rel="manifest" href="./manifest.json" /><link rel="stylesheet" href="./css/style.css" /><meta name="theme-color" content="#31d53d" />
</head><body></body>
<script src="./js/index.js" type="module"></script>
</html>
index.js
/**伪页面历史记录管理类 更新时会访问 fbody.fupdate 函数* 调用push(bodyID)加载新页面* 调用pop()返回上一个f-body*/
class PageHistory {data = []push(bodyID) {if (this.data.length > 1) this.data[this.data.length - 1].scrollY = document.documentElement.scrollTop;let res = this.data.push({bodyID: bodyID,scrollY: 0,});console.log("添加伪页面历史:" + bodyID);document.documentElement.scrollTop = 0;this.updatePage();return res;}pop() {if (this.data.length == 0) return;let res = this.data.pop();let ele = document.querySelector("body>f-body#" + res.bodyID);ele?.remove(); // 真正释放内存console.log("删除伪页面历史:" + res.bodyID);this.updatePage();}updatePage() {for (let i = 0; i < this.data.length; i++) {const element = this.data[i];let qbody = document.querySelector('body>f-body#' + element.bodyID);if (!qbody) {console.log("伪页面历史<" + element.bodyID + ">因元素不存在而被删除");this.data.splice(i, 1);i--;continue;}qbody.style.display = "none";}if (this.data.length >= 1) {let history_item = this.data[this.data.length - 1];let qbody = document.querySelector('body>f-body#' + history_item.bodyID);qbody.style.display = "";if(qbody.fupdate) qbody.fupdate();document.documentElement.scrollTop = history_item.scrollY;}}
}
// 暴露pageHistory到主window下
window.pageHistory = new PageHistory();/**加载伪页面文件(位置: ./fakepage/xxx.html)并构建为shadow-root, 隔离css和js环境* 加载文件并构建带有唯一ID的<f-body>元素, 然后加入到document.body下 * 自动记录伪页面历史 * 自动执行fname文件中<script class="script">元素中的代码 * @param {string} fname 文件名称, 不带路径* @param {string} pageID 唯一页面id, 作为伪页面历史的标识* @param {*} data 附加到 shadow-root.data 上的数据, 可为空* @returns shadow-root: 加载的dom元素(shadow-root)*/
async function loadFakePage(fname, pageID, data) {pageID = pageID + "-" + (new Date() - 0);// if (document.querySelector('body>f-body#' + pageID) !== null) {// console.error("页面ID<" + pageID + ">已存在!");// }const ele = document.createElement('f-body');ele.id = "" + pageID;const res = ele.attachShadow({ mode: 'open' });res.data = data;let resp = await ((await fetch('./fakepage/' + fname)).text());res.innerHTML = resp;document.body.appendChild(ele);pageHistory.push(pageID);const pageScript = res.querySelector('script.script')?.innerText;if (pageScript) (new Function('fbody', pageScript))(res);return res;
}
示例 fakepage
<style>:host {width: 100vw;user-select: none;text-align: center;&>h1 {font-size: 4em;}&>button {font-size: 2em;margin: 5vw;width: 90vw;}}
</style>
<h1>主页面</h1>
<button class="enter">测试按钮</button>
<script class="script">function pageLoad() {let btn = document.createElement('button');btn.innerText = "testing";btn.onclick = () => {fbody.querySelector('h1').innerText = "测试中...";btn.disabled = true;setTimeout(() => {loadFakePage('home.html', 'home');}, 1000);};};pageLoad();
</script>
