当鼠标悬停在 Firefox 中的嵌入式 iframe 上时,防止父页面滚动

Posted

技术标签:

【中文标题】当鼠标悬停在 Firefox 中的嵌入式 iframe 上时,防止父页面滚动【英文标题】:Prevent parent page from scrolling when mouse is over embedded iframe in Firefox 【发布时间】:2015-11-16 20:52:42 【问题描述】:

...不限制 iframe 内的滚动或需要专门命名/标记所有可滚动元素。

想象一下嵌入在父页面中的谷歌地图小部件。当您放大小部件时,显然您不希望父页面滚动。

我认为我的previous question 的答案解决了这个问题:

在 iframe 内滚动时,body 不知道任何关于 那里发生了什么。但是当 iframe 滚动条到达底部或 顶部,它将滚动传递给正文。

取消从 iframe 传播的事件。

但该解决方案在 Firefox 中不起作用,因为 Firefox 不会 - by design - 将 iframe 捕获的事件传播到父页面,但奇怪的是它会滚动父页面。见jsfiddle here。

$('body').bind('mousewheel DOMMouseScroll', onWheel);

function onWheel (e)
    if (e.target === iframe)
        e.preventDefault();
    console.log(e);

那么,当用户在 Firefox 中放大嵌入式 iframe 中的内容时,如何防止页面滚动?

【问题讨论】:

因为 Firefox 使用 DOMMouseScroll 事件,我会尝试将 $('body') 更改为 $(document),也许它可以工作,但我不确定。值得一试 @GOSCHEN 这不是问题,“Firefox 不会 - 按照设计 - 将 iframe 捕获的事件传播到父页面” 如果您仍然可以捕获滚动事件(在父页面上),也许您可​​以根据 iframe 位置检查鼠标位置:如果鼠标在内部,则取消滚动 【参考方案1】:

由于它是 Firefox 中的一个错误,解决方法是直接使用 scroll 事件,而不是 mousewheel / DOMMouseScroll 事件。

我的做法:当用户在iframe 上输入鼠标时,我将标志设置为true,当他将鼠标离开时,我将其设置回false

然后,当用户尝试滚动,但鼠标箭头在 iframe 内时,我会阻止父窗口滚动。但是,不幸的是,您无法使用通常的 e.preventDefault() 方法阻止窗口滚动,因此我们在这里仍然需要另一种解决方法,强制窗口精确滚动到之前的 X 和 Y 位置。

完整代码:

(function(w) 
    var s =  insideIframe: false  

    $(iframe).mouseenter(function() 
        s.insideIframe = true;
        s.scrollX = w.scrollX;
        s.scrollY = w.scrollY;
    ).mouseleave(function() 
        s.insideIframe = false;
    );

    $(document).scroll(function() 
        if (s.insideIframe)
            w.scrollTo(s.scrollX, s.scrollY);
    );
)(window);

我创建了一个立即执行的函数来防止在全局范围内定义 s 变量。

小提琴工作:http://jsfiddle.net/qznujqjs/16/


编辑

由于您的问题没有用 jQuery 标记(尽管在其中,您已经展示了使用该库的代码),因此使用 vanilla JS 的解决方案与上述解决方案一样简单:

(function(w) 
    var s =  insideIframe: false  

    iframe.addEventListener('mouseenter', function() 
        s.insideIframe = true;
        s.scrollX = w.scrollX;
        s.scrollY = w.scrollY;
    );
    
    iframe.addEventListener('mouseleave', function() 
        s.insideIframe = false;
    );

    document.addEventListener('scroll', function() 
        if (s.insideIframe)
            w.scrollTo(s.scrollX, s.scrollY);
    );
)(window);

【讨论】:

这是非常优雅的 hack! @Buzinas 我希望父页面滚动,即使我的鼠标在 iframe 上但在 Firefox 中没有发生,请参阅这个小提琴jsfiddle.net/shmdhussain/jop93dhr/2 谢谢,这项工作非常好! =D,我已经重构了你的第一个代码,但是,我只改变了如何做这些事件。我把它们做成这样:``$('my_container').on('mouseenter', 'iframe' ,function() )''【参考方案2】:

鉴于所有先决条件,我认为以下是在 Firefox 中实现此功能的最明智的方法。

div 包裹你的iframe,它稍微短一点,以便在其中启用垂直滚动:

<div id="wrapper" style="height:190px; width:200px; overflow-y: auto; overflow-x: hidden;">
  <iframe id="iframeid"   src="about:blank">
  </iframe>
</div>

现在您可以将iframe 垂直居中并每次重新定位它 包装器接收到scroll 事件(当用户试图在框架边缘滚动时会发生):

var topOffset = 3;

wrapper.scrollTop(topOffset);

wrapper.on("scroll", function(e) 
    wrapper.scrollTop(topOffset);
);

将此与您之前对 Chrome 的修复相结合,它应该涵盖所有主要浏览器。这是一个工作示例 - http://jsfiddle.net/o2tk05ab/5/

唯一突出的问题是包装器div 上的可见垂直滚动条。有几种方法可以解决它,例如 - Hide scroll bar, but still being able to scroll

【讨论】:

【参考方案3】:

我认为这将解决您的问题 它解决了我的问题

    var myElem=function(event)
  return $(event.toElement).closest('.slimScrollDiv')


$(document).mouseover(function(e)
     window.isOnSub=myElem(e).length>0



)

$(document).on('mousewheel',function(e)
  if(window.isOnSub)  
console.log(e.originalEvent.wheelDelta);      
    if( myElem(e).prop('scrollHeight')-myElem(e).scrollTop()<=myElem(e).height()&&(e.originalEvent.wheelDelta<0))

      e.preventDefault()
     




)

用你想要的元素选择器替换“.slimScrollDiv” 防止鼠标在其上时父滚动

http://jsbin.com/cutube/1/edit?html,js,output

【讨论】:

我不明白,这不仅会阻止父级滚动,还会阻止子级滚动。你能编辑我的 JSFiddle 并向我展示你的解决方案是如何工作的吗?谢谢 感谢您的评论,请再次检查我的答案我已编辑 对不起,我应该更清楚,我见过类似的解决方案,但这取决于具体命名/标记您希望可滚动的元素的需要。这种方法容易出错且不可扩展。我在我原来的问题中将此作为条件,但忘记在这个问题中再次提及。我做了一个编辑现在提到它。

以上是关于当鼠标悬停在 Firefox 中的嵌入式 iframe 上时,防止父页面滚动的主要内容,如果未能解决你的问题,请参考以下文章

Highcharts 鼠标跟踪/鼠标悬停功能在 chrome 上很慢,但在 Firefox 或 IE 上并不慢

嵌入在对象元素中的 SVG 上的鼠标指针悬停/jquery 单击事件不起作用

当鼠标悬停而不是 pyFLTK 中的小部件时如何调用函数?

css3关键帧悬停动画firefox

不用js代码,在selenium里面实现鼠标悬停

在Firefox中禁用主窗口滚动onmouseenter iframe