【问题标题】:Bypass popup blocker on window.open when JQuery event.preventDefault() is set设置 JQuery event.preventDefault() 时绕过 window.open 上的弹出窗口阻止程序
【发布时间】:2012-03-19 20:36:08
【问题描述】:

我想在超链接的点击事件上有条件地显示一个 JQuery 对话框。

我有一个要求,例如在条件 1 上打开一个 JQuery 对话框,如果条件 1 不满足,请导航到其点击事件的“href”标签所引用的页面。

我可以在链接的点击事件上调用一个函数。这个函数现在通过执行另一个 URL(执行我的 Spring 控制器并返回响应)来检查上述条件。

只有 window.open 被弹出窗口阻止程序阻止,所有工作都完美。

$('a[href*=/viewpage?number]').live('click', function(e) {
    e.preventDefault();
    redirectionURL = this.href;
    pageId= getUrlVars(redirectionURL)["number"];
    $.getJSON("redirect/" + pageId, {}, function(status) {
        if (status == null) {
            alert("Error in verifying the status.");
        } else if(!status) {
            $("#agreement").dialog("open");
        } else {
            window.open(redirectionURL);
        }
    });
});

如果我从代码中删除 e.preventDefault();,弹出窗口阻止程序不会阻止页面,但是对于条件 1,它会打开对话框并打开“href”页面。

如果我解决了一个问题,就会给另一个问题带来麻烦。我无法同时对这两种情况作出公正的评价。

你能帮我解决这个问题吗?

一旦解决了这个问题,我还有另一个问题需要解决,即对话 OK 事件的导航 :)

【问题讨论】:

  • 尽量不要使用已弃用的 .live 和指向 .on() 的指针!
  • @EvilP:就像其他人上次对你说的那样,仅在 1.7 及更高版本中。 很多项目仍将在 1.5 或 1.6 上。
  • Downvoter:仅仅因为你不喜欢弹出窗口,这并不意味着这个问题应该被否决。如果一个问题“......没有显示出任何研究成果;如果不清楚或没有用”,则该问题应被否决。这个问题很清楚,看起来并不懒惰,并且源于一个不平凡的因素组合。
  • @T.J.Crowder:他没有具体说明他使用的是哪个版本。所以我应该考虑他正在使用最新版本。如果他使用的是不同的版本,我相信他会提到这一点,因为这样他就会意识到 live 已被弃用,并会解释他为什么使用 .live()。没有人告诉我“最后一次”的时间,所以我觉得你应该让自己休息一下,冷静下来。没必要这么苛刻……
  • 没有收到任何通知。但是,如果有人没有指定他们的版本来考虑他们使用的是最新的,这难道不是正常的吗?我的意思是我必须使用 1.3 是有原因的,而且我知道有一个更新更好的版本。

标签: jquery window.open jquery-callback popup-blocker


【解决方案1】:

弹出窗口拦截器通常只允许window.open处理用户事件(如点击)时使用。在您的情况下,您要调用window.open稍后,而不是在活动期间,因为$.getJSON 是异步的。

你有两个选择:

  1. 做点别的,而不是window.open

  2. 使 ajax 调用同步,这是您通常应该避免的事情,就像瘟疫一样,因为它锁定了浏览器的 UI。 $.getJSON 相当于:

    $.ajax({
      url: url,
      dataType: 'json',
      data: data,
      success: callback
    });
    

    ...因此您可以通过将您的参数映射到上述参数并添加 async: false 来使您的 $.getJSON 调用同步:

    $.ajax({
        url:      "redirect/" + pageId,
        async:    false,
        dataType: "json",
        data:     {},
        success:  function(status) {
            if (status == null) {
                alert("Error in verifying the status.");
            } else if(!status) {
                $("#agreement").dialog("open");
            } else {
                window.open(redirectionURL);
            }
        }
    });
    

    同样,如果您能找到任何其他方式来实现您的目标,我不提倡同步 ajax 调用。但如果你不能,那就去吧。

    以下是由于异步调用而导致测试失败的代码示例:

    Live example | Live source (由于 JSBin 的更改,实时链接不再有效)

    jQuery(function($) {
      // This version doesn't work, because the window.open is
      // not during the event processing
      $("#theButton").click(function(e) {
        e.preventDefault();
        $.getJSON("http://jsbin.com/uriyip", function() {
          window.open("http://jsbin.com/ubiqev");
        });
      });
    });
    

    下面是一个使用同步调用的例子:

    Live example | Live source (由于 JSBin 的更改,实时链接不再有效)

    jQuery(function($) {
      // This version does work, because the window.open is
      // during the event processing. But it uses a synchronous
      // ajax call, locking up the browser UI while the call is
      // in progress.
      $("#theButton").click(function(e) {
        e.preventDefault();
        $.ajax({
          url:      "http://jsbin.com/uriyip",
          async:    false,
          dataType: "json",
          success:  function() {
            window.open("http://jsbin.com/ubiqev");
          }
        });
      });
    });
    

【讨论】:

  • 谢谢一百万。您关于使呼叫同步的建议就像一个魅力。在我可能的下一个处理对话 OK 事件导航的问题中,这同样帮助了我。
  • 作为 T.J.克劳德有 2 个问题悬而未决,[1.找到 window.open] 和 [2.避免 ajax 同步调用] 欢迎对这些建议提出建议,以造福社区。否则,我发现他的答案是上述问题的完美解决方案:)
  • 对我来说,我添加了一个带有 target="_blank" 的链接来提示用户点击。
  • @Evan:你必须直接使用 XHR。 the ticket for deprecating synchronous requests中有一个例子。
  • @mavaze 我认为如果您可以将控制流更改为首先打开窗口(同步),然后执行 AJax 请求(异步),然后使用响应显示错误消息或进行重定向。
【解决方案2】:

只有当用户直接执行某些操作时,您才能调用 window.open 而不会阻止浏览器。 浏览器发送一些标志并确定用户操作打开的窗口。

所以,你可以试试这个场景:

  1. var myWindow = window.open('')
  2. 在此窗口中绘制任何加载消息
  3. 请求完成后,只需调用 myWindow.location = 'http://google.com'

【讨论】:

  • 这在 Safari Mobile 上不起作用(在 iPhone 4 上测试)。我尝试了其他几个想法(例如myWindow.postMessage),但由于 Safari 限制不在后台执行 JavaScript,父窗口永远无法发送该位置更改。
  • @BausTheBig 我在 iPhone 6、IOS8 上测试过。它就像一个魅力。
  • 正在寻找一种方法来使用 Google Analytics 跟踪外部链接,而不会阻止弹出窗口。这正是我所需要的。似乎在 iOS7(实际手机)和 iOS 8(iOS 模拟器)的 iPhone 4s 上运行良好。
【解决方案3】:

事件必须由用户发起的观察帮助我弄清楚了第一部分,但即使在那之后 Chrome 和 Firefox 仍然阻止了新窗口。第二部分是在链接中添加 target="_blank",这在一条评论中有所提及。

总而言之:您需要从用户发起的事件中调用 window.open,在这种情况下单击链接,并且该链接需要具有 target="_blank"。

在下面的示例中,链接使用 class="button-twitter"。

$('.button-twitter').click(function(e) {
  e.preventDefault();
  var href = $(this).attr('href');
  var tweet_popup = window.open(href, 'tweet_popup', 'width=500,height=300');
});

【讨论】:

    【解决方案4】:

    试试这个,它对我有用,

    $('#myButton').click(function () {
        var redirectWindow = window.open('http://google.com', '_blank');
        $.ajax({
            type: 'POST',
            url: '/echo/json/',
            success: function (data) {
                redirectWindow.location;
            }
        });
    });
    

    这是http://jsfiddle.net/safeeronline/70kdacL4/1/的小提琴

    【讨论】:

    • 谢谢,也为我工作 - 如果不是那个小提琴我可能不会相信,哈哈!
    • 这应该是公认的答案!如果您需要异步数据来构建 url,也可以使用 redirectWindow.location.assign('new_url')。
    • 不错的解决方案。继续努力
    • 请测试redirectWindow是否为空!根据不同的浏览器选项,您可能会被阻止。
    【解决方案5】:

    我遇到了这个问题,直到回调返回一些数据,我才准备好我的 url。解决方案是在开始回调之前打开空白窗口,然后在回调返回时设置位置。

    $scope.testCode = function () {
        var newWin = $window.open('', '_blank');
        service.testCode().then(function (data) {
            $scope.testing = true;
            newWin.location = '/Tests/' + data.url.replace(/["]/g, "");
        });
    };
    

    【讨论】:

    • 我使用这个解决方案打开一个新窗口并绕过popupblocker
    • 如果我事先不知道是否需要打开弹出窗口怎么办?如:action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) 所以我不能事先打开一个窗口(以保留它的参考等),如果以后我不会使用它,对吧?
    • 不,它每次都会打开一个新标签,我猜在你不使用它的情况下你不会想要那个。问题是浏览器只允许您在点击功能中打开一个新标签(用户启动的操作),否则弹出窗口阻止程序会将其视为未经用户许可打开新标签的脚本并阻止它。
    • 请测试一下 newWin 是否为空!
    • 为什么?我看不出这是什么原因。
    【解决方案6】:

    必须在与用户启动的事件相同的堆栈(又名 microtask)上创建 Windows,例如点击回调——因此它们不能在以后异步创建。

    但是,您可以创建一个没有 URL 的窗口,然后您可以更改该窗口的 URL,一旦您知道它,甚至可以异步!

    window.onclick = () => {
      // You MUST create the window on the same event
      // tick/stack as the user-initiated event (e.g. click callback)
      const googleWindow = window.open();
    
      // Do your async work
      fakeAjax(response => {
        // Change the URL of the window you created once you
        // know what the full URL is!
        googleWindow.location.replace(`https://google.com?q=${response}`);
      });
    };
    
    function fakeAjax(callback) {
      setTimeout(() => {
        callback('example');
      }, 1000);
    }
    

    现代浏览器会打开带有空白页面的窗口(通常称为about:blank),并且假设您获取 URL 的异步任务相当快,因此生成的 UX 大部分都很好。如果您想在用户等待时将加载消息(或任何内容)呈现到窗口中,您可以使用Data URIs

    window.open('data:text/html,<h1>Loading...<%2Fh1>');
    

    【讨论】:

      【解决方案7】:

      这段代码对我有帮助。希望这可以帮助一些人

      $('formSelector').submit( function( event ) {
      
          event.preventDefault();
      
          var newWindow = window.open('', '_blank', 'width=750,height=500');
      
          $.ajax({
      
              url: ajaxurl,
              type: "POST",
              data: { data },
      
          }).done( function( response ) {
      
              if ( ! response ) newWindow.close();
              else newWindow.location = '/url';
      
          });
      });
      

      【讨论】:

        【解决方案8】:

        尝试使用 a 链接 元素并使用 javascriipt 点击它

        <a id="SimulateOpenLink" href="#" target="_blank" rel="noopener noreferrer"></a>
        

        和脚本

        function openURL(url) {
            document.getElementById("SimulateOpenLink").href = url
            document.getElementById("SimulateOpenLink").click()
        }
        

        这样使用

        //do stuff
        var id = 123123141;
        openURL("/api/user/" + id + "/print") //this open webpage bypassing pop-up blocker
        openURL("https://www.google.com") //Another link
        

        【讨论】:

        • 这避免了我处理空白窗口。
        • 事实证明,这并没有解决我的问题,即 iPhone 将我的窗口阻止为弹出窗口。
        【解决方案9】:
        var url = window.open("", "_blank");
        url.location = "url";
        

        这对我有用。

        【讨论】:

          【解决方案10】:

          我正在使用这种方法来避免我的 React 代码中的弹出窗口阻止程序。它也适用于所有其他 javascript 代码。

          当您在点击事件上进行异步调用时,只需先打开一个空白窗口,然后在异步调用完成时将 URL 写入其中。

          const popupWindow = window.open("", "_blank");
          popupWindow.document.write("<div>Loading, Plesae wait...</div>")
          

          在异步调用成功后,编写以下内容

          popupWindow.document.write(resonse.url)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-06-28
            • 1970-01-01
            • 1970-01-01
            • 2013-04-28
            相关资源
            最近更新 更多