代码之家  ›  专栏  ›  技术社区  ›  clamchoda

跨域iframe element.scrollintoview()safari问题

  •  0
  • clamchoda  · 技术社区  · 6 年前

    我遇到了一个困扰着谷歌的问题,但所有提供的解决方案都不能正常工作。我假设这些解决方案中的大多数都不涉及跨域。

    我有一个网站,我想指示用户用一个(整页)iframe嵌入他们的网站。问题只出现在一些版本的Safari上。iframe中的元素无法滚动到视图中。

    enter image description here

    我注意到,如果我进行相同的域测试,iframe可以使用 window.parent.scrollTo(0,element.top) . 这是可行的,但不是跨域的。另一个奇怪的事情是,没有其他浏览器需要window.parent方法来滚动iframe,只有safari。所有其他浏览器都可以使用 element.scrollIntoView() 在iframe中。请注意,我已经使用 JavaScript workaround 请使用跨协议iframes进行Safari。

    另一个我只在Safari Mobile上看到的问题是,当向下滚动时,引导模式在iframe的顶部出现在视野之外。不过,我敢肯定,如果我们能正确设置滚动位置,我们也应该能够设置模态位置。

    这是我试过的;

     1. window.frames['IFrameName'].document.
        getElementById("elmId").scrollIntoView();
    
    1. Offset trick
    2. JS

    我在这里的最后一个方法(我认为)是使用i frame中的postmessage通知父域来设置帧的滚动位置。

    在我看来,这个问题已经存在了很长时间了。有没有比这更好的方法?

    1 回复  |  直到 6 年前
        1
  •  0
  •   clamchoda    6 年前

    这最终是一个比代码更多的研究。发生的事情是-我有代码可以根据内容调整iframe的大小。

    在所有其他浏览器中,这都可以正常工作,并消除滚动条。原来是野生动物 automatically sizes the Iframe 留下它自己的卷轴。在我的应用程序中,没有静态页面。这使我面临无法使用 scrolling=no 链接中描述的修复。

    在发现了到底发生了什么之后,我采取了另一种方法来解决 elm.scrollIntoView() . 代码更多的是注释,除了重要的部分;

    1. 检测何时应用iframe修复 RequiresIframeScrollFix
    2. 使用 elm.getBoundingClientRect().top 从iframe中获取滚动位置。
    3. 与要滚动的父级通信 window.parent.postMessage
    4. 在父级中接收消息 window.addEventListener('message',...)

    这就是它的样子。

    iFrAME站点

    我们的iframe站点当前将其元素滚动到如下视图中 elm.scrollIntoView(); 我们已将其更改为以下内容。

    if (RequiresIframeScrollFix())
         window.parent.postMessage(elm.getBoundingClientRect().top, "*"); // Tell IFrame parent to do the scrolling. If this is not a test environment, replace "*" with the parent domain.
     else
         elm.scrollIntoView(); // If not scroll into view as usual.
    

    可选:修复iOS iframes中的引导模式定位,使用 elm.getboundingclientrect().top .

    $('#modalId').css('top', elm.getBoundingClientRect().top); // This fixes modal not in view on Safari Iframes.
    

    RequiresIframeScrollFix() 主要是由一些很好的文档代码组成,用来确定我们是在ipad还是iphone上使用iframe。

    // Used to help identify problematic userAgents.
    var debugNavigator = false;
    
    // Detects an issue on mobile where the Parent is an iframe which cannot have it's scroll bars removed.
    // Presumably not a bug as safari will autosize it's iframes: https://salomvary.com/iframe-resize-ios-safari.html
    // Can use "scrolling=no" fix instead if the parent knows the initial size of your iframe.
    function RequiresIframeScrollFix() {
        try {
            // Debug navigator Agent
            if (debugNavigator)
                alert(navigator.userAgent);
    
            // We know this issue happens inside an IFrame on;
            // Safari iPhone
            // Safari iPad
            // Safari Desktop Works fine.
    
            // Check for safari
            var is_safari = navigator.userAgent.indexOf("Safari") > -1;
            // Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
            var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
            if ((is_chrome) && (is_safari)) { is_safari = false; }
    
            // If we need to narrow this down even further we can use a more robust browser detection (https://stackoverflow.com/questions/5916900)
            // Problematic browsers can be adjusted here.
            if (is_safari && inIframe() && (
                    navigator.userAgent.match(/iPad/i) ||
                    navigator.userAgent.match(/iPhone/i)
                    ))
                return true;
            else
                return false;
    
        } catch (e) {
            alert(e.message);
        }
    }
    
    // (https://stackoverflow.com/questions/326069/)
    function inIframe() {
        try {
            return window.self !== window.top;
        } catch (e) {
            return true;
        }
    }
    

    父网站

    我们的父站点包含Safari Mobile自动调整大小的iframe。因此,父站点现在有自己的滚动条,而不是iframe。我们将监听器设置在父站点内,以便在它接收到来自iframed站点的消息时自动滚动。

    // Safari Mobile Iframe Cross Domain Scroll Fix.
    window.onload = function () {
         // Calback function to process our postMessages.
         function receiveMessage(e) {
              try {
                   // Set the scroll position from our postMessage data.
                   // Non-Test pages should uncomment the line below.
                   //if (e.origin.includes("your-iframe-domain.com"))
                   window.scrollTo(0, e.data);
               }
               catch (err) {
               }
          }
    
          // Setup and event to receives messages form our iframe (or window)
          window.addEventListener('message', receiveMessage);
    }
    

    希望这能帮助其他人在手机上分析Safari iFrame问题。另外,如果我忽略了一个更好的解决方案,请告诉我。