如何解决IE11的localStorage事件两次或根本不在iframe中?
我猜这是一个错误,但我一直没有find任何关于这个问题的讨论。
众所周知,IE10将(针对spec)本地触发存储事件(即在触发事件的同一全局执行环境中),但是IE11似乎更偏离规范( http://www.w3.org / TR / webstorage / ),当涉及到同域的iframes:
- 如果iframeembedded在触发存储事件的页面中,则该事件将在该iframe内触发TWICE。
- 如果iframeembedded在与触发存储事件的页面不同的页面中,则该事件在该iframe内根本不会触发。
- 如果事件是由iframe触发的 ,则会在本地触发TWICE,并在同一页面中embedded的任何其他iframe中触发TWICE,但在其他页面的iframe中触发。
您可以通过在两个单独的选项卡中打开以下链接来进行testing: http : //hansifer.com/main.html
任何人都有这个奇怪的见解吗?
最后testing版本: IE v11.0.9600.16476 (更新2016-08-13:显然它是相关的“更新版本”,而不是IE的“关于”对话框中报告的“版本”)
链接到错误报告: https : //connect.microsoft.com/IE/feedback/details/811546/ie11-localstorage-events-fire-twice-or-not-at-all-in-iframes
更新2015-10-26
我只是注意到,这似乎是固定在v11.0.9600.18059,虽然我不知道什么时候修复下降,因为它似乎没有在任何最近的KB引用。
不幸的是,IE11 localStorage事件在其他方面仍然存在exception(尽pipe这些是与本文中提出的问题分开的):
-
IE在触发事件的localStorage设置或移除的窗口上下文中引发localStorage事件。 localStorage事件只能在相同来源的外部窗口上下文中引发。 (更新:在EdgeHTML 13.10586中工作)
-
当存储项被添加/删除时,IE对
e.oldValue/e.newValue
使用空string而不是null
。 (更新:在EdgeHTML 13.10586仍然是一个问题) -
IE调用localStorage事件处理程序非确定性BEFORE或AFTER设置/删除后生效,而不是始终如一。
更新2015-12-24
看来这个bug被转移到边缘(testing的EdgeHTML 13.10586)
更新2016-02-02
韦尔普,没关系。 在IE v11.63.10586.0 (更新2016-08-13:显然它是相关的“更新版本”,而不是在IE的关于对话框中报告的“版本”)中再次观察到这个错误。
更新2016-08-13
这个现在似乎在IE(更新版本11.0.34)中是固定的,虽然存储事件仍然在原始窗口中被触发,违反规范(一个已知的长期存在的问题)。
我发现这个包含在IE 2016年6月14日安全更新中的知识库 ,尽pipe根据其描述,它只涉及上面的第二个项目符号。
至于Edge(经过testing的EdgeHTML 14.14393),现在看起来这个问题现在已经解决了,但是还有一个新问题:存储事件不是跨同一页面的同源帧触发的。
我在这里分别向MS报告。
如果您想禁止多次调用某个事件(无论调用的原因如何),请使用标志来阻止后续事件。 有几个策略:
0.1。 基于时间的节stream。 假设你有一个函数“func”,并且你希望它在200ms内只被调用一次:
function func(){ if (document.func_lock) return; document.func_lock=true; // block future calls setTimeout(function(){document.func_lock=null;},300); }
当同时触发多个事件时,您可以预期所有这些事件在300ms窗口内到达。 上面的代码可以通过利用定时器句柄来简化:
function func(){ if (document.func_lock) return; document.func_lock=setTimeout(function(){return;},300); }
当计时器到期时,锁将被自动删除。
0.2。 通过使用callback删除标志。 这个过程是微不足道的,所以我不会在这里发布示例代码。
在标志位置方面,您可以使用任何独特的DOM对象。 由于我不知道应用程序的上下文,因此我只是在这里使用“文档”。 您也可以使用特定于您的应用程序的散列键,因为您已经在处理本地存储。 这个概念是一样的。
我能够通过使用window.parent
以这种方式在iframe中注册事件来解决问题:
Iframe页面
var win = window.parent || window.opener || window; win.addEventListener('storage', handleLocalStorageEvent, false); function handleLocalStorageEvent(e) { console.log('IFRAME local storage event', e); var sdf = document.getElementById('sdf'); sdf.innerHTML = sdf.innerHTML + 'Storage Event => (' + e.newValue + ')<br>'; }
免责声明:请注意,此解决scheme旨在解决(解决)IE11问题。 无论如何,这意味着或build议这适用于所有的浏览器。