Как предотвратить действия iFrame от вызова внешней страницы для ее прокрутки
Во-первых, я знаю, что есть много вопросов об этом явлении, но ни один из обходных решений, данных до сих пор, не помог бы в ситуации, в которой я здесь.
![enter image description here]()
Окружающая среда:
Мой код находится в Outer iFrame внутри страницы, которую я не контролирую. Он имеет размер, чтобы соответствовать всему моему контенту, поэтому прокрутка не происходит внутри моего iFrame. Скорее, внешняя страница может прокручивать ее вверх и вниз, чтобы просмотреть ее содержимое.
Проблема:
У меня есть внутренний iFrame, содержащий сторонние объявления, которые я не могу контролировать. Если внутренний iFrame запускает любую из следующих команд Javascript, внешняя страница прокручивает все вниз, чтобы отобразить внутренний iFrame:
Вот демо-коллега, собранный (подождите 5 секунд, чтобы он начал)
Решения, которые не работают:
- Если бы я контролировал внешнюю страницу, я мог бы прослушивать событие onScroll и предотвращать прокрутку страницы, если это не было из события мыши или события вверх/вниз. Однако из-за соображений безопасности мой внешний iFrame не может получить доступ к главной странице или предотвратить прокрутку главной страницы вверх или вниз.
- Я мог бы перезаписать все эти Javascript-методы, упомянутые выше, чтобы они не работали, однако объявления в моем внутреннем iFrame фактически создают свои собственные внутренние iFrames, которые имеют эту функциональность и вызывают одну и ту же проблему.
- События не распространяются, и я вижу, что мой iFrame может не дойти до главной страницы. Браузер, кажется, прослушивает непосредственно самую внутреннюю iFrame.
Ответы
Ответ 1
Возможно, есть и другие способы решения этой проблемы, но одно довольно простое решение состоит в том, чтобы принять неудобные iframes из естественной компоновки сайта , позиционируя их как fixed
.
Тогда единственной оставшейся проблемой может быть заставить их вести себя так, как если бы они были частью естественного макета. Но эти задачи, похоже, имеют посредственную сложность по сравнению с исходной проблемой.
Кроме того, в вашем конкретном случае вышеупомянутый подход работает довольно корректно. Поскольку внешний iframe не прокручивается, а его высота соответствует его высоте содержимого: вам просто нужно вставить - для каждого iframe - местозаполнитель, соответствующий его размеру...
Ответ 2
Если вы можете отказаться от поддержки IE10 и ниже, а iframes
- это тот же домен, вы можете использовать комбинацию из вашего решения номер 2 (переписать методы) и события mutation
.
Вам нужно сначала перебрать все iframes
уже в DOM и удалить ненужные функции, а также, возможно, также очистить нежелательные интервалы. И на каждом document
вы добавляете mutation
observer
, который будет запускать те же скрипты на added nodes
, если они iframes
. Таким образом, вы должны иметь рекурсивную функцию, проходящую через все фреймы в начале, и функцию для удаления методов, очистки интервалов и добавления наблюдателей на каждом iFrame
. И как только добавляется iFrame
, вы запускаете то же самое на нем. Что-то вроде этого:
Рекурсивная функция:
var to_cancel = ["scrollIntoView","blur","focus"];
window.onload = function(){iterate_window_object(window)};
function iterate_window_object(cur_win){
remove_methods(cur_win);
for(var i=0;i<cur_win.frames.length;i++){
remove_methods(cur_win.frames[i])
if(cur_win.frames[i].length>0){
iterate_window_object(cur_win.frames[i])
}
}
}
Функция очистки:
function remove_methods(cur_win){
for(var j=0;j<to_cancel.length;j++){
cur_win.Element.prototype[to_cancel[j]] = {}
}
for (var k = 0; k < 999;k++){
cur_win.clearInterval(k);
}
cur_win.setInterval = {};
cur_win.observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
for(var k=0;k<mutation.addedNodes.length;k++){
var added_node = mutation.addedNodes[k]
if(added_node.tagName == "IFRAME"){
remove_methods(added_node.contentWindow);
added_node.contentWindow.onload = function(){iterate_window_object(added_node.contentWindow)};
}
};
});
});
cur_win.config = { childList: true };
cur_win.observer.observe(cur_win.document.getElementsByTagName('body')[0], cur_win.config);
}
Вероятно, способ сделать это лучше, самая сложная часть - это возможность модифицировать методы до их вызова. И здесь он немного переборчив, потому что он выполняет итерацию через новый iframes
, так что если iframe добавляется с уже добавленным iframes
, они также берутся. Это, вероятно, не нужно.
Таким образом, это может быть решение, но mutation
события не поддерживаются IE10 и ниже.