如何防止iFrame操作导致外部页面滚动到它

时间:2015-06-12 18:28:51

标签: javascript iframe browser scroll

首先,我知道有很多关于这种现象的问题,但到目前为止给出的解决方法都不会对我在这里的情况有所帮助。

enter image description here

环境: 我的代码位于我无法控制的页面内的外部iFrame中。它的大小适合我的所有内容,因此我的iFrame中不会发生滚动。相反,外部页面可以向上和向下滚动以查看其内容。

问题: 我有一个内部iFrame,持有我无法控制的第三方广告。如果内部iFrame运行以下任何Javascript命令,则外部页面会向下滚动所有内容以使内部iFrame进入视图:

  1. 模糊并专注于其中的元素
  2. window.location.href或document.location.hash到其中的锚点。

  3. 内部元素的scrollIntoView

  4. Here is a demo a colleague put together(等待5秒钟开始)

    无法解决的解决方案

    1. 如果我控制了外页,我可以收听onScroll事件并阻止页面滚动,如果它不是来自鼠标滚轮或键上/下事件。但是,由于安全原因,我的外部iFrame无法访问主页面或阻止主页面向上或向下滚动。
    2. 我可以覆盖上面提到的所有Javascript方法,因此它们无法正常工作 - 但是,我内部iFrame中的广告实际上创建了自己的内部iFrame,这些iFrame具有该功能并导致相同的问题。
    3. 没有任何事件被传播,我可以看到我的iFrame可能会停止到达主页面。浏览器似乎直接监听最里面的iFrame。

2 个答案:

答案 0 :(得分:3)

也许有其他一些方法可以解决这个问题,但一个非常直接的解决方案是通过将它们定位为fixed ,从网站的自然布局中取出麻烦的iframe。 / p>

然后唯一剩下的挑战可能是强制他们表现得好像他们是自然布局的一部分。但与原始问题相比,这项任务似乎具有平庸的复杂性。

此外,在您的特定情况下,上述方法开箱即用。由于外部iframe不可滚动且其高度与其内容高度匹配:您只需为每个iframe插入一个与其对应大小匹配的占位符...

答案 1 :(得分:1)

如果您可以删除IE10及以下支持且iframes是同一个域,则可以使用解决方案编号2(重写方法)和mutation事件的组合。 您需要首先遍历DOM中已有的所有iFrames并删除不需要的功能,并且还可能清除不需要的间隔。在每个document上添加一个mutation observer,如果它们是added nodes,则会在iFrames上运行相同的脚本。所以你在开始时有一个遍历所有iframe的递归函数,以及一个删除方法,清除间隔和在每个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,那么它们也会被带到。{可能没有必要。 所以它可能是一个解决方案,但IE10及以下版本不支持mutation个事件。