设置JQuery event.preventDefault()时,跳过window.open上的弹出窗口阻止程序


98

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

我有一个条件,例如关于condition1的请求,请打开一个JQuery对话,如果不满足condition1的条件,请导航到该问题的“ href”标记所引用的页面。

我可以在链接的click事件上调用函数。现在,该函数通过执行另一个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();从代码中删除,popoup阻止程序不会阻止该页面,但是对于condition1,它随后会打开对话框以及打开“ href”页面。

如果我解决了一个问题,则会给另一个问题。我无法同时兼顾这两种情况。

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

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


1
尽量不要使用已过时的.live和指向.on()的指针!
mas-designs

@EvilP:就像其他人上次对您说的那样,仅在1.7及更高版本中。一个很大的项目仍然会在1.5或1.6。
TJ Crowder'3

10
Downvoter:仅仅因为您不喜欢弹出窗口,并不意味着这个问题应该被拒绝。如果某个问题“……未显示任何研究成果;尚不清楚或没有用”,则应予以否决。问题很明显,似乎并不懒惰,并且源于各种因素的共同作用。
TJ Crowder 2012年

@TJCrowder:他没有指定他使用的版本。因此,我应该考虑他正在使用最新版本。如果他使用的是其他版本,那么我肯定他会提到,因为那时他将意识到不赞成使用live的事实,并会解释为什么他使用了.live()。没有人告诉我“最后一次”,所以我觉得你应该休息一下,让自己冷静下来。不需要如此苛刻……
mas-designs

对此没有任何通知。但是,如果有人没有指定他们的版本来考虑他们使用的是最新版本,这是不正常的吗?我的意思是我必须使用1.3是有原因的,并且我知道存在一个更新更好的版本的事实。
mas-designs

Answers:


144

弹出窗口阻止程序通常仅处理用户事件(如点击)window.open时使用才允许。就您而言,您将稍后调用,而不是在事件发生期间进行调用,因为它是异步的。window.open $.getJSON

您有两种选择:

  1. 做其他事情,而不是window.open

  2. 使ajax调用同步化,这通常是您应该避免的事情,例如鼠疫,因为它会锁定浏览器的UI。$.getJSON等效于:

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

    ......所以你可以让你$.getJSON通过映射你的PARAMS以上,加入通话同步async: false

    $.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调用。但是,如果做不到,那就去吧。

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

    现场示例 | 实时源 (由于对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");
        });
      });
    });

    这是一个使用同步调用起作用的示例:

    现场示例 | 实时源 (由于对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");
          }
        });
      });
    });

3
太感谢了。您提出的使呼叫同步的建议就像一个魅力。同样在下一个可能处理对话的OK事件导航的问题上也帮了我。
2012年

由于TJ Crowder留下了2个问题,[1。查找window.open的替代方法]和[2。避免提出ajax同步调用]的建议,对于社区有益。另外,我发现他的回答是上述问题的完美解决方案:)
mavaze 2012年

4
对我来说,我添加了一个带有target =“ _ blank”的链接来提示用户单击。
hiroshi'4

1
@Evan:您必须直接使用XHR。凭单中有一个不赞成使用同步请求的示例。
TJ Crowder 2012年

2
@mavaze我认为,如果可以更改控制流以首先打开窗口(同步),然后执行AJax请求(异步),然后使用响应显示错误消息或进行重定向,则可以避免这两个问题。
Stijn de Witt

61

您可以仅在用户直接执行某些操作时调用window.open,而不会阻止浏览器。浏览器发送一些标志,并确定由用户操作打开的窗口。

因此,您可以尝试这种情况:

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

2
这在Safari Mobile(在iPhone 4上测试)上不起作用。我尝试了其他一些想法(例如myWindow.postMessage),但是由于Safari的限制,即在后台不执行JavaScript,因此父窗口永远无法发送该位置更改。
roundrobin 2014年

我在iPhone 6,IOS8上测试了@BausTheBig。它像魅力一样运作。
lvarayut 2015年

一直在寻找一种跟踪Google Analytics(分析)外部链接而又不会阻止弹出窗口的方法。这正是我所需要的。似乎可以在iOS7(实际电话)和iOS 8(iOS模拟器)的iPhone 4s上正常工作。
notacouch 2015年

37

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

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

1
我使用此解决方案打开了一个新窗口,并绕过了popupblocker
VeldMuijz

如果我事先不知道是否需要打开弹出窗口怎么办?如:在 action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) 这样的情况下,如果以后不使用它,我将无法手动打开窗口(以保留其引用等),对吗?
路易兹

不,它每次都会打开一个新选项卡,我猜您在不使用它的情况下不希望这样做。问题是浏览器仅允许您在点击功能(用户启动的操作)中打开新标签页,否则弹出窗口阻止程序会将此视为未经用户许可打开新标签页的脚本并将其阻止。
KnuturO

请测试一下newWin是否为空!
FrancescoMM

为什么呢 我认为没有理由。
KnuturO

18

试试这个,对我有用

$('#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/


1
谢谢,也为我工作-如果不是那样,我可能不会相信,哈哈!
rmcsharry

3
这应该是公认的答案!如果您需要异步数据来构建url,也可以使用redirectWindow.location.assign('new_url')。
matheusr

不错的解决方案。继续努力
Shah NIral

请测试redirectWindow是否为null!根据不同的浏览器选项,您是否会被阻止。
FrancescoMM

8

Windows必须与用户启动的事件(例如,单击回调)在同一堆栈(也称为microtask)上创建,因此以后不能异步创建它们。

但是,您可以创建一个没有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>');

3

这段代码对我有帮助。希望这对某些人有帮助

$('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';

    });
});

3

尝试使用链接元素,然后使用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

这为我避免了处理空白窗口。
深思275,2018年

事实证明,这无法解决我的问题,因为iPhone阻止了我的窗口作为弹出窗口。
仔细思考

2

观察到事件必须由用户发起,这帮助我弄清楚了事件的第一部分,但是即使在那之后,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');
});


1

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

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

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

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

popupWindow.document.write(resonse.url)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.