让 iframe 页面强制刷新的方法

在复杂的后台类系统中,为了简单的接入祖传项目、外部不可控页面时,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 属性发生了变更。但是这里只是简单的处理,健全的逻辑还应当考虑 hashquerystring 等存在的情况,实现上会稍微繁琐一些。另外添加时间戳参数的方式改变了实际的 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 基本可以得到正常的反馈。

点赞 (0)

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Captcha Code