以下内容仅仅是个人经过测试后的猜测!!如果知道官方的定义的,请再评论区指条明路~
iframe
把 iframe 考虑成浏览器新开的 tab 页,是比较合适的~
嵌入 iframe 的页面
假设页面上只嵌入了一个 iframe 元素。以下内容顶层网页用 top
表示,嵌入的 iframe 网页用 iframe
表示。
浏览器的后退
浏览器的后退按钮是面向用户的,既作用整个页面,包含 top
和 iframe
。top
上的 history 和 iframe
上的 history 的 length 是相同的。window.history.length === window.top.history.length
。
测试及结论
Chrome 上测试
序号 | 操作 |
top page |
iframe page |
备注 |
---|---|---|---|---|
1 | 加载页面 | 11 | 21 | |
2 | iframe 上点击链接修改 iframe | 11 | 22 | location.assign 或 pushState |
3 | iframe 上点击链接修改 iframe | 11 | 23 | location.assign 或 pushState |
4 | top 执行 location.replace 更新 hash | 12 | 23 | top 上单页应用更新 |
5 | 点击浏览器后退 | 11 | 23 |
步骤 4 替换了步骤 3 产生的历史记录,浏览器认为从步骤 2 到步骤 4 只有 top 参与了历史改变,所有只有 top 被回退 |
6 | 点击浏览器后退 | 11 | 21 |
步骤 2 回退到步骤 1 仅 iframe 参与了历史改变,修改 iframe page 到步骤 1 时的状态 |
7 | 点击浏览器前进 | 11 | 22 |
步骤 1 前进到步骤 2 仅 iframe 参与了历史改变,修改 iframe page 到步骤 2 时的状态 |
Chrome 上结论
Chrome 的 history,不仅利用了每一步 top
和 iframe
的状态,还利用了这一步是由那个 window 引起的。点击回退只会使参与了 history 的那个 window 回到上一步该有的状态,点击前进类似。Firefox 跟 Chrome 类似。
Safari 上测试
序号 | 操作 |
top page |
iframe page |
备注 |
---|---|---|---|---|
1 | 加载页面 | 11 | 21 | |
2 | iframe 上点击链接修改 iframe | 同步骤 1,11 | 22 | location.assign 或 pushState |
3 | iframe 上点击链接修改 iframe | 同步骤 1,11 | 23 | location.assign 或 pushState |
4 | top 执行 location.replace 更新 hash | 12 | 23 | top 上单页应用更新,将 top 最近的一条历史替换了,现在步骤 1 2 3 的 top 历史是 12 了 |
5 | 点击浏览器后退 | 12 | 22 |
步骤 4 替换了步骤 1 top 产生的历史记录。此时浏览器后退,top 应为 12;iframe 由步骤 3 回到步骤 2,应为 22 |
6 | 点击浏览器后退 | 12 | 21 |
top 和 iframe 组合 |
7 | 点击浏览器前进 | 12 | 22 | 同上 |
Safari 上结论
在 Safari 上 top
和 iframe
是分开的,然后再根据 history 的形成过程进行组合。
在 Safari 上的结论就相对 Chrome 来说要简单一些,但使用 replace 后整个 history 的逻辑对用户来说可能就难以理解了(如上面例子)。测试中 top
的 page 地址都取至控制台输出 location,有可能与地址栏展示的网址不一致,见下面存在的问题。
存在的问题
- Safari 上发现存在 location 和地址栏网址不一致的情况。在上面的测试例子中, 步骤 5 到步骤 7 地址栏显示的还是页面 11 对应的网址,但是控制台打印的 location 确是页面 21 的地址。地址栏的链接应该是分开保存的,上一步是啥就是啥吧,不会被脚本篡改。
- 发现多次执行 location.replace 后,不会引起 react-router 的 browserHistory.listen,也不会传新的状态给组件。复现步骤(SPA):1 -> 2 -> 3 -> 执行 replace(2) -> 3 -> 执行 replace(2) 不生效;测试的时候 replace 只修改了 hash。(react-router: "^2.0.0")