Bỏ qua trình chặn cửa sổ bật lên trên window.open khi JQuery event.preventDefault () được đặt


98

Tôi muốn hiển thị hộp thoại JQuery có điều kiện khi nhấp vào sự kiện của một siêu kết nối.

Tôi có một yêu cầu như trên condition1 mở đối thoại JQuery và nếu điều kiện1 không được đáp ứng, hãy điều hướng đến trang được tham chiếu bởi thẻ 'href' của sự kiện nhấp chuột đang được đề cập.

Tôi có thể gọi một hàm trên sự kiện nhấp chuột của liên kết. Hàm này hiện kiểm tra điều kiện đã nói bằng cách thực thi một URL khác (thực thi bộ điều khiển Spring của tôi và trả về phản hồi).

Tất cả đều hoạt động hoàn hảo chỉ có window.open bị chặn bởi trình chặn cửa sổ bật lên.

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

Nếu tôi xóa e.preventDefault();khỏi mã, trình chặn popoup sẽ không chặn trang, tuy nhiên đối với condition1 thì nó sẽ mở hộp thoại cũng như mở trang 'href'.

Nếu tôi giải quyết một vấn đề, nó sẽ tạo ra vấn đề cho một vấn đề khác. Tôi không thể đưa ra công lý cho cả hai điều kiện đồng thời.

Bạn có thể giúp tôi giải quyết vấn đề này xin vui lòng?

Khi điều này được giải quyết, tôi có một vấn đề khác cần giải quyết, tức là điều hướng trên sự kiện OK của đối thoại :)


1
cố gắng không sử dụng .live không được dùng nữa và một con trỏ đến .on ()!
mas-

@EvilP: Như những người khác đã nói với bạn lần trước, chỉ từ 1.7 trở lên. Rất nhiều dự án sẽ vẫn ở trên 1.5 hoặc 1.6.
TJ Crowder

10
Phản đối: Chỉ vì bạn không thích cửa sổ bật lên, điều đó không có nghĩa là câu hỏi này nên bị phản đối. Một câu hỏi nên bị loại bỏ nếu nó "... không cho thấy bất kỳ nỗ lực nghiên cứu nào; nếu không rõ ràng hoặc không hữu ích" . Câu hỏi rõ ràng, không có vẻ lười biếng, và bắt nguồn từ sự kết hợp không tầm thường của các yếu tố.
TJ Crowder

@TJCrowder: Anh ấy không nói rõ mình đang sử dụng phiên bản nào. Vì vậy, tôi nên xem xét rằng anh ấy đang sử dụng phiên bản mới nhất. Nếu anh ấy đang sử dụng một phiên bản khác, tôi chắc chắn anh ấy sẽ đề cập đến điều đó bởi vì THÌ anh ấy SẼ nhận thức được thực tế là tính năng trực tiếp không được chấp nhận và sẽ giải thích TẠI SAO anh ấy lại sử dụng .live (). Không ai nói với tôi lần "cuối cùng" nên tôi nghĩ bạn nên nghỉ ngơi và bình tĩnh lại. Không cần phải quá khắc nghiệt ...
mas-

Không có bất kỳ thông báo nào về điều đó. Nhưng có bình thường không khi xem xét điều đó nếu ai đó không chỉ định phiên bản của họ để coi rằng họ đang sử dụng phiên bản mới nhất? Ý tôi là tôi phải sử dụng 1.3 là có lý do và tôi biết thực tế là có một phiên bản mới hơn và tốt hơn.
mas-thiết kế

Câu trả lời:


144

Trình chặn cửa sổ bật lên thường sẽ chỉ cho phép window.opennếu được sử dụng trong quá trình xử lý sự kiện của người dùng (như một lần nhấp). Trong trường hợp của bạn, bạn đang gọi window.open sau , không phải trong sự kiện, vì $.getJSONkhông đồng bộ.

Bạn có hai lựa chọn:

  1. Làm điều gì đó khác, thay vì window.open.

  2. Làm cho cuộc gọi ajax đồng bộ, đây là điều bạn thường nên tránh như bệnh dịch hạch vì nó khóa giao diện người dùng của trình duyệt. $.getJSONtương đương với:

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

    ... và do đó, bạn có thể thực hiện $.getJSONcuộc gọi của mình đồng bộ bằng cách ánh xạ các tham số của bạn với các tham số ở trên và thêm 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);
            }
        }
    });

    Một lần nữa, tôi không ủng hộ các lệnh gọi ajax đồng bộ nếu bạn có thể tìm thấy bất kỳ cách nào khác để đạt được mục tiêu của mình. Nhưng nếu bạn không thể, bạn sẽ làm được.

    Dưới đây là một ví dụ về mã không thành công trong quá trình kiểm tra do lệnh gọi không đồng bộ:

    Ví dụ trực tiếp | Nguồn trực tiếp (Các liên kết trực tiếp không còn hoạt động do các thay đổi đối với 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");
        });
      });
    });

    Và đây là một ví dụ hoạt động, sử dụng lệnh gọi đồng bộ:

    Ví dụ trực tiếp | Nguồn trực tiếp (Các liên kết trực tiếp không còn hoạt động do các thay đổi đối với 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
Cảm ơn rất nhiều. Đề xuất của bạn về việc thực hiện đồng bộ hóa cuộc gọi hoạt động như một sự quyến rũ. Điều tương tự đã giúp tôi trong vấn đề tiếp theo có thể xảy ra là xử lý điều hướng trong sự kiện OK của đối thoại.
mê cung

Vì TJ Crowder đã bỏ ngỏ 2 câu hỏi, [1. tìm thay thế cho window.open] và [2. tránh cuộc gọi đồng bộ ajax] đề xuất về những đề xuất đó được hoan nghênh vì lợi ích của cộng đồng. Khác tôi tìm thấy câu trả lời của mình một giải pháp hoàn hảo cho biết câu hỏi :)
mavaze

4
Đối với tôi, tôi đã thêm một liên kết với target = "_ blank" để nhắc người dùng nhấp vào.
hiroshi

1
@Evan: Bạn sẽ phải sử dụng XHR trực tiếp. Có một ví dụ trong phiếu cho các yêu cầu đồng bộ không dùng nữa .
TJ Crowder vào

2
@mavaze Tôi nghĩ rằng bạn có thể tránh được cả hai vấn đề nếu bạn có thể thay đổi luồng điều khiển để mở cửa sổ trước tiên, (đồng bộ hóa), sau đó thực hiện yêu cầu AJax (không đồng bộ) và sau đó sử dụng phản hồi để hiển thị thông báo lỗi hoặc thực hiện chuyển hướng.
Stijn de Witt

61

bạn có thể gọi window.open mà không cần trình duyệt chặn chỉ khi người dùng thực hiện trực tiếp một số hành động. Trình duyệt gửi một số cờ và xác định cửa sổ đó được mở bởi hành động của người dùng.

Vì vậy, bạn có thể thử kịch bản này:

  1. var myWindow = window.open ('')
  2. vẽ bất kỳ thông báo đang tải nào trong cửa sổ này
  3. khi yêu cầu hoàn tất, chỉ cần gọi myWindow.location = ' http://google.com '

2
Điều này không hoạt động trên Safari Mobile (đã thử nghiệm trên iPhone 4). Tôi đã thử một số ý tưởng khác (ví dụ myWindow.postMessage) nhưng do hạn chế của Safaris là không thực thi JavaScript trong nền, cửa sổ mẹ không bao giờ có thể gửi thay đổi vị trí đó.
roundrobin

@BausTheBig Tôi đã thử nghiệm trên iPhone 6, IOS8. Nó làm việc như một say mê.
lvarayut

đang tìm cách theo dõi các liên kết bên ngoài với Google Analytics mà không bị chặn cửa sổ bật lên. Đây chính xác là những gì tôi cần. Có vẻ như hoạt động tốt trên iPhone 4s trong iOS7 (điện thoại thực tế) và iOS 8 (Trình mô phỏng iOS).
notacouch

37

Tôi gặp sự cố này và tôi chưa chuẩn bị sẵn url của mình cho đến khi lệnh gọi lại sẽ trả về một số dữ liệu. Giải pháp là mở cửa sổ trống trước khi bắt đầu gọi lại và sau đó chỉ cần đặt vị trí khi gọi lại trở lại.

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

1
Tôi đã sử dụng giải pháp này để mở một cửa sổ mới và bỏ qua các popupblocker
VeldMuijz

Điều gì sẽ xảy ra nếu tôi không biết trước nếu tôi cần mở cửa sổ bật lên? Như trong: action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) Vì vậy, tôi không thể mở một cửa sổ trước đó (để giữ tham chiếu của nó, v.v.) nếu sau này tôi không sử dụng nó, phải không?
Luiz

Không, nó sẽ mở một tab mới mọi lúc và tôi đoán bạn sẽ không muốn điều đó trong trường hợp bạn không sử dụng nó. Vấn đề là trình duyệt sẽ chỉ cho phép bạn mở một tab mới trong chức năng nhấp chuột (hành động do người dùng thực hiện) nếu không trình chặn cửa sổ bật lên sẽ coi đây là một tập lệnh mở tab mới mà không có sự cho phép của người dùng và chặn nó.
KnuturO

Vui lòng kiểm tra nếu newWin là null!
FrancescoMM

Tại sao ? Tôi thấy không có lý do cho điều này.
KnuturO

18

hãy thử cái này, nó phù hợp với tôi,

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

Là fiddle cho http://jsfiddle.net/safeeronline/70kdacL4/1/ này


1
Cảm ơn, đã làm việc cho tôi - nếu không phải vì trò đùa đó thì có lẽ tôi đã không tin điều đó, lol!
rmcsharry

3
Đây phải là câu trả lời được chấp nhận! Bạn cũng có thể sử dụng redirectWindow.location.assign ('new_url') nếu bạn cần dữ liệu không đồng bộ để tạo url.
mathusr

Giải pháp tốt. Hãy duy trì nó
Shah NIral

Vui lòng kiểm tra nếu redirectWindow là null! Theo các tùy chọn trình duyệt khác nhau, bạn có thể bị chặn hoặc không.
FrancescoMM

8

Windows phải được tạo trên cùng một ngăn xếp (hay còn gọi là microtask ) với sự kiện do người dùng khởi tạo, ví dụ: cuộc gọi lại lần nhấp - vì vậy, chúng không thể được tạo không đồng bộ sau này.

Tuy nhiên, bạn có thể tạo một cửa sổ mà không có URL và sau đó bạn có thể thay đổi URL của cửa sổ đó khi bạn đã biết , ngay cả khi không đồng bộ!

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);
}

Các trình duyệt hiện đại sẽ mở cửa sổ với một trang trống (thường được gọi là about:blank) và giả sử tác vụ không đồng bộ của bạn để lấy URL diễn ra khá nhanh, thì UX kết quả hầu hết đều ổn. Thay vào đó, nếu bạn muốn hiển thị thông báo đang tải (hoặc bất kỳ thứ gì) vào cửa sổ trong khi người dùng chờ đợi, bạn có thể sử dụng URI dữ liệu .

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

3

Mã này giúp tôi. Hy vọng điều này sẽ giúp một số người

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

Hãy thử sử dụng một phần tử liên kết và nhấp vào nó bằng javascriipt

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

và kịch bản

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

Sử dụng nó như thế này

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

Điều này tránh đối phó với cửa sổ trống cho tôi.
ponder275

Hóa ra điều này không giải quyết được vấn đề của tôi khi iPhone chặn cửa sổ của tôi dưới dạng cửa sổ bật lên.
ponder275

2

Quan sát rằng sự kiện phải do người dùng bắt đầu đã giúp tôi tìm ra phần đầu tiên của điều này, nhưng ngay cả sau đó Chrome và Firefox vẫn chặn cửa sổ mới. Phần thứ hai là thêm target = "_ blank" vào liên kết, được đề cập trong một nhận xét.

Tóm lại: bạn cần gọi window.open từ một sự kiện do người dùng khởi tạo, trong trường hợp này là nhấp vào một liên kết và liên kết đó cần có target = "_ blank".

Trong ví dụ bên dưới, liên kết đang sử dụng 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

Tôi đang sử dụng phương pháp này để tránh trình chặn cửa sổ bật lên trong mã React của mình. nó cũng sẽ hoạt động trong tất cả các mã javascript khác.

Khi bạn đang thực hiện cuộc gọi không đồng bộ trên sự kiện nhấp chuột, trước tiên chỉ cần mở một cửa sổ trống và sau đó viết URL vào đó sau khi lệnh gọi không đồng bộ sẽ hoàn tất.

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

về thành công của cuộc gọi không đồng bộ, hãy viết như sau

popupWindow.document.write(resonse.url)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.