在复杂的后台类系统中,为了简单的接入祖传项目、外部不可控页面时,iframe
是一个较为简单合适的方案。
在域名相同的情况下,可以很简单的通过 $iframe.contentWindow.location.reload(true)
方法,强制刷新 iframe 页面。
当域名不同时,由于同源策略的限制,该 API 变为不可用。此时可用的刷新方案有两种:
- 调用
replace
API:$iframe.contentWindow.location.replace(url)
- 重设
src
属性:$iframe.src = $iframe.src
这两种方法本质上是相似的。但是假若 iframe 中的 url 没有发生过变化,你会发现 onload
等事件都会触发,但页面状态却会保持不变,而且会完整的缓存起来。于是就出现了修改 src
地址,添加无意义参数的方式让页面地址改变的方案。大致参考如下:
const $iframe = document.querySelector('iframe.show'); const src = $iframe.src.split('?_t')[0]; // 变更 src 实现 iframe 刷新 $iframe.src = `${src}?_t=${Date.now()}`;
该示例中以添加一个时间戳的方式让 src
属性发生了变更。但是这里只是简单的处理,健全的逻辑还应当考虑 hash
、querystring
等存在的情况,实现上会稍微繁琐一些。另外添加时间戳参数的方式改变了实际的 url 地址,看上去并不是太优雅。
如果不修改 src 属性值,是否有其他的方案呢?
查阅 MDN 上关于 iframe 的文档,你可以发现关于 src
有这么一段描述:
使用 about:blank 值可以嵌入一个遵从同源策略的空白页。
那么我们可以先将 src
设置为 about:blank
,然后再设置回去,是不是就可以实现刷新了呢。使用如下代码进行测试:
const $iframe = document.querySelector('iframe.show'); const src = $iframe.src; $iframe.src = 'about:blank'; setTimeout(() => $iframe.src = src, 16);
可以看到效果是符合预期的。另外根据文档描述,移除 src
属性也会导致 about:blank
被载入,故也可这样实现:
const $iframe = document.querySelector('iframe.show'); const src = $iframe.src; $iframe.removeAttribute('src'); setTimeout(() => $iframe.setAttribute('src', src), 50);
需要注意的是,setTimeout
的延时应大于一帧,否则会得不到更新。实际测试大于 16ms 基本可以得到正常的反馈。