ข้ามตัวป้องกันป๊อปอัปบน window.open เมื่อตั้งค่า JQuery event.preventDefault ()


99

ฉันต้องการแสดงกล่องโต้ตอบ JQuery ตามเงื่อนไขเมื่อคลิกเหตุการณ์ของไฮเปอร์ลิงก์

ฉันมีข้อกำหนดเช่นใน condition1 ให้เปิดกล่องโต้ตอบ 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();จากโค้ดตัวป้องกันป๊อปอัปจะไม่บล็อกหน้าอย่างไรก็ตามสำหรับ condition1 จะเปิดกล่องโต้ตอบและเปิดหน้า 'href'

ถ้าฉันแก้ปัญหาหนึ่งมันจะสร้างปัญหาให้กับอีกคน ฉันไม่สามารถให้ความยุติธรรมกับเงื่อนไขทั้งสองพร้อมกันได้

คุณช่วยฉันแก้ปัญหานี้ได้ไหม

เมื่อแก้ไขได้แล้วฉันมีปัญหาอื่นที่ต้องแก้ไขเช่นการนำทางในเหตุการณ์ตกลงของบทสนทนา :)


1
พยายามอย่าใช้. live ที่เลิกใช้งานและตัวชี้ไปที่. บน ()!
mas-designs

@EvilP: อย่างที่คนอื่นพูดกับคุณครั้งที่แล้วแค่ 1.7 ขึ้นไป จำนวนมากของโครงการจะยังคงอยู่ใน 1.5 หรือ 1.6
TJ Crowder

10
Downvoter: เพียงเพราะคุณไม่ชอบป๊อปอัปนั่นไม่ได้หมายความว่าคำถามนี้ควรถูกลดคะแนน คำถามที่ควรจะ downvoted ถ้ามัน"... ไม่ได้แสดงความพยายามวิจัยใด ๆ ถ้าไม่ชัดเจนหรือไม่เป็นประโยชน์" คำถามนั้นชัดเจนดูเหมือนไม่น่าเกียจและเกิดจากการผสมผสานของปัจจัยที่ไม่สำคัญ
TJ Crowder

@TJCrowder: เขาไม่ได้ระบุว่าใช้เวอร์ชันไหน ดังนั้นฉันควรพิจารณาว่าเขากำลังใช้เวอร์ชันล่าสุด หากเขาใช้เวอร์ชันอื่นฉันแน่ใจว่าเขาจะพูดถึงเรื่องนี้เพราะเขาจะทราบถึงความจริงที่ว่าการถ่ายทอดสดเลิกใช้งานแล้วและจะอธิบายว่าทำไมเขาถึงใช้. live () ไม่เคยมีใครบอกฉันครั้ง "สุดท้าย" ดังนั้นฉันว่าคุณควรหยุดพักและสงบสติอารมณ์ ไม่จำเป็นต้องรุนแรงขนาดนี้ ...
mas-designs

ไม่ได้รับการแจ้งเตือนใด ๆ เกี่ยวกับเรื่องนั้น แต่เป็นเรื่องปกติหรือไม่ที่จะพิจารณาว่าหากใครบางคนไม่ระบุเวอร์ชันของตนเพื่อให้พิจารณาว่าใช้เวอร์ชันล่าสุด ฉันหมายความว่าฉันต้องใช้ 1.3 ด้วยเหตุผลและฉันตระหนักดีว่ามีเวอร์ชันใหม่และดีกว่า
mas-designs

คำตอบ:


144

โดยทั่วไปตัวบล็อกป๊อปอัปจะอนุญาตก็ต่อwindow.openเมื่อใช้ในระหว่างการประมวลผลเหตุการณ์ของผู้ใช้ (เช่นการคลิก) ในกรณีของคุณคุณกำลังโทรหาในwindow.open ภายหลังไม่ใช่ในระหว่างกิจกรรมเนื่องจาก$.getJSONเป็นแบบอะซิงโครนัส

คุณมีสองทางเลือก:

  1. window.openทำอย่างอื่นมากกว่า

  2. ทำให้ ajax โทรแบบซิงโครนัสซึ่งเป็นสิ่งที่ปกติคุณควรหลีกเลี่ยงเช่นโรคระบาดเนื่องจากมันล็อก UI ของเบราว์เซอร์ $.getJSONเทียบเท่ากับ:

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

    ... และเพื่อให้คุณสามารถ$.getJSONโทรแบบซิงโครนัสได้โดยการแมปพารามิเตอร์ของคุณกับด้านบนและเพิ่ม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
ขอบคุณล้าน คำแนะนำของคุณในการโทรแบบซิงโครนัสทำงานได้อย่างมีเสน่ห์ สิ่งเดียวกันนี้ช่วยฉันในเรื่องถัดไปที่เป็นไปได้ของการจัดการการนำทางในเหตุการณ์ตกลงของบทสนทนา
mavaze

ขณะที่ TJ Crowder เปิดคำถามไว้ 2 ข้อ [1. ค้นหาทางเลือกแทน window.open] และ [2. หลีกเลี่ยงการโทรแบบซิงโครนัส ajax] ยินดีต้อนรับข้อเสนอแนะเกี่ยวกับสิ่งเหล่านี้เพื่อประโยชน์ของชุมชน อย่างอื่นฉันพบว่าคำตอบของเขาเป็นคำตอบที่สมบูรณ์แบบสำหรับคำถามดังกล่าว :)
mavaze

4
สำหรับฉันฉันเพิ่มลิงก์ที่มี target = "_ blank" เพื่อแจ้งให้ผู้ใช้คลิก
hiroshi

1
@ อีวาน: คุณจะต้องใช้ XHR โดยตรง มีตัวอย่างในตั๋วสำหรับการเลิกใช้คำขอซิงโครนั
TJ Crowder

2
@mavaze ฉันคิดว่าคุณสามารถหลีกเลี่ยงปัญหาทั้งสองได้หากคุณสามารถเปลี่ยนขั้นตอนการควบคุมเพื่อเปิดหน้าต่างก่อน (ซิงค์) จากนั้นทำตามคำขอ AJax (async) จากนั้นใช้การตอบกลับเพื่อแสดงข้อความแสดงข้อผิดพลาดหรือทำการเปลี่ยนเส้นทาง
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) แต่เนื่องจากข้อ จำกัด ของ Safaris ไม่ให้เรียกใช้ JavaScript ในพื้นหลังหน้าต่างหลักจึงไม่สามารถส่งการเปลี่ยนแปลงตำแหน่งนั้นได้
roundrobin

@BausTheBig ฉันทดสอบบน iPhone 6, IOS8 มันทำงานได้อย่างมีเสน่ห์
lvarayut

กำลังมองหาวิธีติดตามลิงก์ภายนอกด้วย Google Analytics โดยไม่ถูกบล็อกป๊อปอัป นี่คือสิ่งที่ฉันต้องการ ดูเหมือนว่าจะทำงานได้ดีบน iPhone 4s ใน iOS7 (โทรศัพท์จริง) และ iOS 8 (iOS Simulator)
notacouch

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) ดังนั้นฉันจึงไม่สามารถเปิดหน้าต่างก่อนมือได้ (เพื่อเก็บข้อมูลอ้างอิง ฯลฯ ) ถ้าในภายหลังฉันจะไม่ใช้มันใช่ไหม?
Luiz

มันจะไม่เปิดแท็บใหม่ทุกครั้งและฉันเดาว่าคุณคงไม่ต้องการสิ่งนั้นในกรณีที่คุณไม่ได้ใช้มัน สิ่งนี้คือเบราว์เซอร์จะอนุญาตให้คุณเปิดแท็บใหม่ในฟังก์ชันการคลิกเท่านั้น (การดำเนินการที่ผู้ใช้เริ่มต้น) มิฉะนั้นตัวบล็อกป๊อปอัปจะเห็นสิ่งนี้เป็นสคริปต์ที่เปิดแท็บใหม่โดยไม่ได้รับอนุญาตจากผู้ใช้และบล็อก
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
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ! คุณยังสามารถใช้ redirectWindow.location.assign ('new_url') หากคุณต้องการข้อมูล async เพื่อสร้าง url
matheusr

ทางออกที่ดีเก็บมันไว้
Shah NIral

โปรดทดสอบว่า redirectWindow เป็นโมฆะ! ตามตัวเลือกเบราว์เซอร์ที่แตกต่างกันคุณจะถูกบล็อกหรือไม่
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) และสมมติว่างาน async ของคุณเพื่อรับ URL นั้นค่อนข้างรวดเร็ว UX ที่ได้ส่วนใหญ่จะใช้ได้ดี หากคุณต้องการแสดงข้อความโหลด (หรืออะไรก็ได้) ในหน้าต่างในขณะที่ผู้ใช้รอคุณสามารถใช้URI ข้อมูลได้

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

สิ่งนี้หลีกเลี่ยงการจัดการกับหน้าต่างว่างสำหรับฉัน
ponder275

ปรากฎว่าสิ่งนี้ไม่ได้ช่วยแก้ปัญหาของฉันที่ iPhone ปิดกั้นหน้าต่างของฉันเป็นป๊อปอัป
ponder275

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

ฉันใช้วิธีนี้เพื่อหลีกเลี่ยงตัวป้องกันป๊อปอัปในรหัสการตอบสนองของฉัน มันจะทำงานในรหัสจาวาสคริปต์อื่น ๆ ทั้งหมดด้วย

เมื่อคุณทำการโทรแบบ async เมื่อคลิกเหตุการณ์ให้เปิดหน้าต่างว่างก่อนจากนั้นจึงเขียน URL ในภายหลังเมื่อการเรียกแบบ async เสร็จสมบูรณ์

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

ในความสำเร็จของการโทรแบบ async ให้เขียนสิ่งต่อไปนี้

popupWindow.document.write(resonse.url)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.