在复杂的后台类系统中,为了简单的接入祖传项目、外部不可控页面时,iframe
是一个较为简单合适的方案。
在域名相同的情况下,可以很简单的通过 $iframe.contentWindow.location.reload(true)
方法,强制刷新 iframe 页面。
当域名不同时,由于同源策略的限制,该 API 变为不可用。此时可用的刷新方案有两种:
- 调用
replace
API:$iframe.contentWindow.location.replace(url)
- 重设
src
属性:$iframe.src = $iframe.src
这两种方法本质上是相似的。但是假若 iframe 中的 url 没有发生过变化,你会发现 onload
等事件都会触发,但页面状态却会保持不变,而且会完整的缓存起来。于是就出现了修改 src
地址,添加无意义参数的方式让页面地址改变的方案。大致参考如下:
1 2 3 4 5 | 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
,然后再设置回去,是不是就可以实现刷新了呢。使用如下代码进行测试:
1 2 3 4 5 | const $iframe = document.querySelector( 'iframe.show' ); const src = $iframe.src; $iframe.src = 'about:blank' ; setTimeout(() => $iframe.src = src, 16); |
可以看到效果是符合预期的。另外根据文档描述,移除 src
属性也会导致 about:blank
被载入,故也可这样实现:
1 2 3 4 5 | const $iframe = document.querySelector( 'iframe.show' ); const src = $iframe.src; $iframe.removeAttribute( 'src' ); setTimeout(() => $iframe.setAttribute( 'src' , src), 50); |
需要注意的是,setTimeout
的延时应大于一帧,否则会得不到更新。实际测试大于 16ms 基本可以得到正常的反馈。