Как работать с локальными событиями IE11, которые срабатывают дважды или вообще не работают в iframe?
Я предполагаю, что это ошибка, но я не смог найти об этом никаких обсуждений.
Известно, что IE10 будет (против spec) событий пожарной памяти локально (т.е. в том же глобальном контексте выполнения, из которого было вызвано событие), но IE11, похоже, еще больше отклоняется от спецификации (http://www.w3.org/TR/webstorage/), когда речь идет о iframe того же домена:
- если iframe встроен в страницу, вызвавшую событие хранения, событие запустит TWICE в этом iframe.
- Если iframe встроен в страницу, отличную от той, которая вызвала событие хранения, событие не будет срабатывать вообще внутри этого iframe.
- Если событие запускается из iframe, оно будет срабатывать TWICE локально и TWICE в любом другом iframe, встроенном в ту же страницу, но совсем не в iframe других страниц.
Вы можете проверить это, открыв следующую ссылку на двух отдельных вкладках: http://hansifer.com/main.html
У кого-нибудь есть понимание этого причудливости?
Последняя проверенная версия: IE v11.0.9600.16476 (обновление 2016-08-13: по-видимому, это "обновленная версия", которая имеет значение, а не "Версия", как указано в диалоговом окне "О программе" )
Ссылка на отчет об ошибке: https://connect.microsoft.com/IE/feedback/details/811546/ie11-localstorage-events-fire-twice-or-not-at-all-in-iframes
ОБНОВЛЕНИЕ 2015-10-26
Я только заметил, что это, по-видимому, исправлено в версии 11.9.9600.18059, хотя я не могу сказать, когда исправление было сброшено, поскольку оно, похоже, не упоминается ни в одном недавнем КБ.
К сожалению, события локального хранилища IE11 по-прежнему являются аберрантными по-другому (хотя это отдельные говядины из проблемы, изложенной в этом сообщении):
-
IE вызывает события localStorage в контексте окна, из которого был вызван набор или удаление localStorage, вызвавшее событие. localStorage события должны быть подняты только в контексте внешнего окна того же происхождения. (обновление: работа в EdgeHTML 13.10586)
-
IE использует пустую строку вместо null
для e.oldValue/e.newValue
, когда элементы хранения добавляются/удаляются. (обновление: все еще проблема в EdgeHTML 13.10586)
-
IE вызывает обработчик события localStorage недетерминированно либо до начала, либо после установки/удаления вступает в силу вместо последовательно ПОСЛЕ.
ОБНОВЛЕНИЕ 2015-12-24
Похоже, что эта ошибка была перенесена на Edge (протестировано EdgeHTML 13.10586)
ОБНОВЛЕНИЕ 2016-02-02
Вельп, неважно. Эта ошибка снова наблюдается в IE v11.63.10586.0 (обновление 2016-08-13: по-видимому, это "обновленная версия", которая имеет значение, а не "Версия", как указано в диалоговом окне "О программе" )
ОБНОВЛЕНИЕ 2016-08-13
Теперь это исправлено в IE (Update Version 11.0.34), хотя события хранения все еще запущены в исходном окне, против spec (известный давний вопрос, как упоминалось выше).
Я нашел этот KB, который был включен в IE 14 июня, 2016 "Обновление безопасности" , хотя в соответствии с его описанием он обращается только ко второй марке.
Что касается Edge (проверено EdgeHTML 14.14393), похоже, что эта проблема теперь исправлена, но есть новая проблема: события хранения не запускаются в кадрах одинакового происхождения той же страницы.
Я сообщил об этом отдельно для MS здесь.
Ответы
Ответ 1
Если вы когда-либо хотите отключить событие от вызова несколько раз, независимо от причины вызова, используйте флаг для блокировки последующих событий. Существует несколько стратегий:
0,1. основанный на времени дросселирование. предположим, что у вас есть функция func, и вы хотите, чтобы ее вызывали только один раз за 200 мсек:
function func(){
if (document.func_lock) return;
document.func_lock=true; // block future calls
setTimeout(function(){document.func_lock=null;},300);
}
При одновременном запуске нескольких событий вы можете ожидать, что все они попадут в окно 300 мс. Вышеприведенный код можно упростить, воспользовавшись дескриптором таймера:
function func(){
if (document.func_lock) return;
document.func_lock=setTimeout(function(){return;},300);
}
Когда таймер истекает, блокировка автоматически удаляется.
0,2. Удалите флаг с помощью обратного вызова. Процесс тривиальный, поэтому я не буду размещать здесь образец кода.
В терминах размещения флага вы можете использовать любой уникальный объект DOM. Поскольку я не знаю контекста вашего приложения, я просто использую "документ" здесь. Вы также можете использовать хеш-ключи, которые относятся к вашему приложению, поскольку вы уже имеете дело с локальным хранилищем. Концепция одинаков.
Ответ 2
Мне удалось обойти проблему, используя 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>';
}
Отказ от ответственности: Обратите внимание, что это решение предназначено для устранения проблемы (IE7). Каким-либо образом предполагается или предлагается, чтобы это применимо ко всем браузерам.