Javascript 在safari 11中打开多个弹出窗口

Javascript 在safari 11中打开多个弹出窗口,javascript,safari,Javascript,Safari,自9月20日safari 11更新以来,以下代码(Javascript)一次只打开一个窗口(在safari 10.1上,它会打开所有窗口) 在safari 11中有可能做到这一点吗?如果有,如何做到 我的代码(只是一个示例): 更新: 浏览器首选项设置为启用弹出窗口且不阻止任何内容 如果我在每个打开的窗口之间设置一个至少0.5秒的“setTimeout()”,代码就可以工作了——这可能是因为safari的新更新不想让我用太多的弹出窗口“垃圾邮件”用户 更新:此问题和解决方案自Safari 13起

自9月20日safari 11更新以来,以下代码(Javascript)一次只打开一个窗口(在safari 10.1上,它会打开所有窗口)

在safari 11中有可能做到这一点吗?如果有,如何做到

我的代码(只是一个示例):

更新:

  • 浏览器首选项设置为启用弹出窗口且不阻止任何内容
  • 如果我在每个打开的窗口之间设置一个至少0.5秒的“setTimeout()”,代码就可以工作了——这可能是因为safari的新更新不想让我用太多的弹出窗口“垃圾邮件”用户

  • 更新:此问题和解决方案自Safari 13起仍然有效。

    首先,以下是我在测试中观察到的Safari 11的行为:

    • 始终允许打开一个弹出窗口(即使选中了全局“阻止弹出窗口”设置)。选中“阻止弹出窗口”时,对弹出窗口的
      窗口
      对象的访问将受到限制(未选中“阻止弹出窗口”时不是这种情况)
    • 正如您所描述的,当取消选中“阻止弹出窗口”时,必须延迟多个
      window.open
      调用(在我的测试中需要>1s)
    • 当选中“阻止弹出窗口”时,似乎只允许打开一个弹出窗口(尽管使用了延迟)
    因此,您已经发现了一种解决此问题的方法:添加延迟

    这里还有一种方法可以让您在不需要延迟的情况下打开多个弹出窗口,它使用的知识是,当“阻止弹出窗口”被取消选中时,每个窗口可以毫不延迟地打开一个弹出窗口。考虑到示例中的三个弹出窗口,以下是一般流程:

  • 在您的域上打开一个弹出窗口(空白页)
  • 通过注入加载时执行此操作的脚本,将下一个弹出窗口的打开委派给此弹出窗口
  • 将第一个弹出窗口重定向到所需的URL
  • 重复此操作,直到打开所有弹出窗口
  • 以下是我为处理此流而构建的内容:

    /**
     * Handle the passed hrefs for Safari, which requires special/different
     * handling than other browsers. Open each one in a new window (popup)
     * and delegate the opening of the next popup to each new popup. Handle
     * Safari's global popup blocker setting and inform the primary page
     * (via postMessage) when the blocker is enabled, so a notification can
     * be shown to the user.
     *
     * @param  {Array}    hrefs             hrefs of popups to open
     * @param  {Function} safariPopupOpener Self reference. Required for
     *                                      injecting into next popup.
     * @param  {Window}   primaryWindow     Reference to the primary page
     *                                      Window object. Required for
     *                                      sending postMessage back.
     * @param  {string}   blockedMessage    Message body to send back in
     *                                      postMessage.
     */
    var safariPopupOpener = function(
        hrefs,
        safariPopupOpener,
        primaryWindow,
        blockedMessage
    ) {
        var newWindow = window.open('//url/of/the/blank/page/on/your/domain');
        var popupOpenerScript = document.createElement('script');
    
            // Must add these all to the popup's window object as the
            // execution context of opener() below where they're used is the
            // next popup, not the current window
            newWindow.openAllResultHrefs = hrefs;
            newWindow.openAllResultOpener = safariPopupOpener;
            newWindow.primaryWindow = primaryWindow;
            newWindow.blockedMessage = blockedMessage;
    
            /**
             * Logic to inject into the popup
             */
            function opener() {
                var hrefsCopy = window.openAllResultHrefs.slice();
    
                // Delete the first item from the array for injecting into
                // the next popup
                hrefsCopy.shift();
    
                if (hrefsCopy.length > 0) {
                    // Even when popups are blocked in Safari, one popup is
                    // always allowed to open. However any other popups
                    // opened sequentially are blocked. Also, access to the
                    // one popup's window object is restricted, so this
                    // tries to open the second popup, if window object is
                    // restricted (which occurs before another popup is
                    // opened), catches the resulting error, closes the
                    // first popup and sends a message back to the primary
                    // page that popups are blocked.
                    try {
                        window.openAllResultOpener(
                            hrefsCopy,
                            window.openAllResultOpener,
                            window.primaryWindow,
                            window.blockedMessage
                        );
                    } catch (e) {
                        // Optional: Send a message back to the primary page that
                        // popups have been blocked
                        window.primaryWindow.postMessage(
                            window.blockedMessage,
                            window.primaryWindow.origin
                        );
    
                        // Close the (first) popup window (first because
                        // we only reach this case when popups are blocked
                        // and we've only successfully opened one popup)
                        window.close();
                    }
                }
    
                // Redirect to the popup href
                window.location.href = window.openAllResultHrefs[0];
            }
    
        // Inject the self-executing opener function so it'll run on load in
        // the opened popup
        popupOpenerScript.innerHTML = '(' + opener.toString() + '());';
        newWindow.addEventListener('load', function() {
            // Append the script to the new window's body
            this.document.body.appendChild(popupOpenerScript);
        });
    }
    
    • 注意,我还检测到阻塞并将
      postMessage
      发送回主窗口,以便它能够处理阻塞(例如,向用户显示消息)。因此,在主页面上需要一个
      消息
      侦听器
    • postMessage
      可能不是必需的,但当弹出窗口被阻止时,我无法访问
      窗口。opener
      。可能还有很多改进的空间,但我已经在这方面花费了太多时间:-)

    可能是因为safari默认设置无法启用新的windows弹出窗口。您必须配置浏览器以接受弹出窗口。嗨,马特,谢谢您的回答!我没有使用你的代码(主要是因为我很难理解),但我确实理解了它背后的想法(每个窗口打开下一个弹出窗口),而且它起了作用!这是一个有点工作要做到这一点,但至少它的工作:)非常感谢你,不用担心。超时对于我的用例来说并不是很有用,所以它有点必要。不过我的大脑还是很痛!
    /**
     * Handle the passed hrefs for Safari, which requires special/different
     * handling than other browsers. Open each one in a new window (popup)
     * and delegate the opening of the next popup to each new popup. Handle
     * Safari's global popup blocker setting and inform the primary page
     * (via postMessage) when the blocker is enabled, so a notification can
     * be shown to the user.
     *
     * @param  {Array}    hrefs             hrefs of popups to open
     * @param  {Function} safariPopupOpener Self reference. Required for
     *                                      injecting into next popup.
     * @param  {Window}   primaryWindow     Reference to the primary page
     *                                      Window object. Required for
     *                                      sending postMessage back.
     * @param  {string}   blockedMessage    Message body to send back in
     *                                      postMessage.
     */
    var safariPopupOpener = function(
        hrefs,
        safariPopupOpener,
        primaryWindow,
        blockedMessage
    ) {
        var newWindow = window.open('//url/of/the/blank/page/on/your/domain');
        var popupOpenerScript = document.createElement('script');
    
            // Must add these all to the popup's window object as the
            // execution context of opener() below where they're used is the
            // next popup, not the current window
            newWindow.openAllResultHrefs = hrefs;
            newWindow.openAllResultOpener = safariPopupOpener;
            newWindow.primaryWindow = primaryWindow;
            newWindow.blockedMessage = blockedMessage;
    
            /**
             * Logic to inject into the popup
             */
            function opener() {
                var hrefsCopy = window.openAllResultHrefs.slice();
    
                // Delete the first item from the array for injecting into
                // the next popup
                hrefsCopy.shift();
    
                if (hrefsCopy.length > 0) {
                    // Even when popups are blocked in Safari, one popup is
                    // always allowed to open. However any other popups
                    // opened sequentially are blocked. Also, access to the
                    // one popup's window object is restricted, so this
                    // tries to open the second popup, if window object is
                    // restricted (which occurs before another popup is
                    // opened), catches the resulting error, closes the
                    // first popup and sends a message back to the primary
                    // page that popups are blocked.
                    try {
                        window.openAllResultOpener(
                            hrefsCopy,
                            window.openAllResultOpener,
                            window.primaryWindow,
                            window.blockedMessage
                        );
                    } catch (e) {
                        // Optional: Send a message back to the primary page that
                        // popups have been blocked
                        window.primaryWindow.postMessage(
                            window.blockedMessage,
                            window.primaryWindow.origin
                        );
    
                        // Close the (first) popup window (first because
                        // we only reach this case when popups are blocked
                        // and we've only successfully opened one popup)
                        window.close();
                    }
                }
    
                // Redirect to the popup href
                window.location.href = window.openAllResultHrefs[0];
            }
    
        // Inject the self-executing opener function so it'll run on load in
        // the opened popup
        popupOpenerScript.innerHTML = '(' + opener.toString() + '());';
        newWindow.addEventListener('load', function() {
            // Append the script to the new window's body
            this.document.body.appendChild(popupOpenerScript);
        });
    }