Tránh trình chặn cửa sổ bật lên của trình duyệt


172

Tôi đang phát triển luồng xác thực OAuth hoàn toàn bằng JavaScript và tôi muốn hiển thị cho người dùng cửa sổ "cấp quyền truy cập" trong cửa sổ bật lên, nhưng nó bị chặn.

Làm cách nào tôi có thể ngăn chặn các cửa sổ bật lên được tạo bởi window.openhoặc window.showModalDialogbị chặn bởi các trình chặn cửa sổ bật lên của các trình duyệt khác nhau?


11
Ngay cả khi điều đó là có thể (tôi không biết), nếu mọi người sử dụng trình chặn cửa sổ bật lên, bạn nên tôn trọng nó. Hầu hết các trình duyệt hiển thị thông báo khi một trang web cố gắng mở một cửa sổ bật lên để họ vẫn có thể nhìn thấy nó nếu họ muốn. Bạn có thể đưa ra một nhận xét trên trang web của mình rằng một số nội dung sẽ mở trong cửa sổ bật lên và người dùng nên cho phép nội dung đó để tiếp tục.
Felix Kling

5
Cách thực hành tốt nhất sẽ giống như: 1) Thực hiện thành công 2) Đóng cửa sổ và đóng cửa lại và sợ hãi trước đám đông những người bảo trợ web khó chịu 3) Hãy ăn năn, loại bỏ pop-up-busta-busta và tôn trọng khán giả của bạn.
Alex Mcp

Alex và Felix, tôi đã cập nhật câu hỏi. Tôi sẽ không sử dụng kiến ​​thức cho cái ác :). Cảm ơn!
Pablo Fernandez

9
Tôi muốn thêm rằng việc bỏ qua trình chặn cửa sổ bật lên có thể thực sự đang cố gắng làm cho trải nghiệm người dùng tốt hơn. Trong một ví dụ tôi đang làm việc bây giờ, chúng tôi đang sử dụng một ứng dụng Javascript (dựa trên ExtJS) và chúng tôi đang cố gắng để người dùng thanh toán bằng paypal. Chúng tôi đang cung cấp cho họ một nút mà họ có thể nhấp để khởi chạy paypal trong một cửa sổ mới, nhưng một số phiên bản IE nhất định đang chặn nút đó dưới dạng cửa sổ bật lên (mặc dù đó là một lần bấm nút). Nếu bây giờ họ kích hoạt cửa sổ bật lên, màn hình tải lại và dưới dạng ứng dụng JavaScript, chúng ta sẽ mất trạng thái cửa sổ và họ phải bắt đầu lại. Vì vậy, thực sự: vấn đề là IE là ngu ngốc.
NateDSaint

1
@FelixKling Vâng, điều đó là có thể. Các nhà sản xuất trình duyệt đã nghĩ về điều này. Mở một cửa sổ bật lên là OK theo ý định của người dùng (được báo hiệu bởi người dùng nhấp vào một liên kết hoặc nút). Trình chặn popup nên tôn trọng ý định của người dùng. Nếu trình chặn cửa sổ bật lên của IE thì không, đó là trình chặn cửa sổ bật lên có lỗi. Người dùng sử dụng trình chặn cửa sổ bật lên để ngăn tập lệnh mở cửa sổ bật lên theo ý muốn, không phải để chặn cửa sổ bật lên mà chính họ đã cố mở (bằng cách nhấp vào nút hoặc liên kết).
Stijn de Witt

Câu trả lời:


286

Nguyên tắc chung là các trình chặn cửa sổ bật lên sẽ tham gia nếu window.openhoặc tương tự được gọi từ javascript không được gọi bằng hành động trực tiếp của người dùng . Nghĩa là, bạn có thể gọi window.openđể phản hồi lại bằng cách nhấp vào nút mà không bị chặn bởi trình chặn cửa sổ bật lên, nhưng nếu bạn đặt cùng một mã trong một sự kiện hẹn giờ thì nó sẽ bị chặn. Độ sâu của chuỗi cuộc gọi cũng là một yếu tố - một số trình duyệt cũ hơn chỉ nhìn vào người gọi ngay lập tức, các trình duyệt mới hơn có thể quay lại một chút để xem liệu trình gọi của người gọi có phải là một cú click chuột hay không.


2
Thật thú vị, các cửa sổ bật lên được bắt đầu thông qua một sự kiện thay đổi được liên kết với một yếu tố được chọn sẽ bị chặn (trong Chrome, không phải FF), ngay cả khi sự kiện đó được bắt đầu bằng hành động trực tiếp của người dùng, như nhấp chuột. Mặc dù nếu bị ràng buộc với một đầu vào, chúng được cho phép. Lạ thật.
ccnokes

6
Không ai nói trình duyệt là nhất quán. : P
dthorpe

8
Thông qua các thử nghiệm tôi đã hiểu rằng độ sâu ngăn xếp không liên quan gì đến trình chặn cửa sổ bật lên. Nó thực sự kiểm tra xem window.open có được gọi trong vòng 1 giây sau khi người dùng hành động hay không. Đã thử nghiệm trong Chrome 46 và Firefox 42.
Mesqalito

Thời gian chờ 1 giây có thể bị phá vỡ trong cả hai trình duyệt cho phép lượng thời gian không xác định bằng cách sử dụng câu trả lời của @ tj-crowder trên trang này .. có URL bạn đang gọi qua ajax là một số php (hoặc bất cứ điều gì) sử dụng chế độ ngủ ( ) trong một khoảng thời gian trước khi nó trả lời. Trình duyệt sẽ treo trong khi nó 'tải' trang .. sau đó kích hoạt cửa sổ bật lên khi nhận được phản hồi. Tuy nhiên, trong Chrome, bạn phải thêm cảnh báo () ngay trước ajax () để thực hiện thủ thuật này.
phô trương

184

Dựa trên mẹo rất hữu ích của Jason Sebring , và trên những thứ được đề cập ở đâyđó , tôi đã tìm thấy một giải pháp hoàn hảo cho trường hợp của mình:

Mã giả với đoạn mã Javascript:

  1. ngay lập tức tạo một cửa sổ bật lên trống trên hành động của người dùng

    var importantStuff = window.open('', '_blank');

    Tùy chọn: thêm một số thông báo "chờ". Ví dụ:

    a) Một trang HTML bên ngoài: thay thế dòng trên bằng

    var importantStuff = window.open('http://example.com/waiting.html', '_blank');

    b) Văn bản: thêm dòng sau bên dưới dòng trên:

    importantStuff.document.write('Loading preview...');
  2. điền nội dung khi sẵn sàng (ví dụ: khi cuộc gọi AJAX được trả lại)

    importantStuff.location.href = 'http://shrib.com';

Làm phong phú cuộc gọi đến window.openvới bất kỳ tùy chọn bổ sung nào bạn cần.

Tôi thực sự sử dụng giải pháp này để chuyển hướng mailto và nó hoạt động trên tất cả các trình duyệt của tôi (windows 7, Android). Các _blankchút giúp cho mailto chuyển hướng để làm việc trên điện thoại di động, btw.

Kinh nghiệm của bạn? Bất kỳ cách nào để cải thiện điều này?


1
? Vậy bạn sẽ làm gì nếu không phải do hành động của người dùng trong trình duyệt? Ví dụ của tôi, sau khi người dùng xác thực với máy chủ, nó phải mở một tab mới
Don Cheadle

@mmcrae đừng làm vậy. Dù bạn định làm gì, có một cách tốt hơn cửa sổ bật lên. Nếu không, rất có thể tôi sẽ không bao giờ muốn xem trang web của bạn. Các trình duyệt ngày nay đảm bảo bạn không thể làm điều đó - xem câu trả lời của @dthorpe .
Swiss Mister

5
Whatever it is you intend to do, there is a better way than a popup windowcười lớn? Khái quát hóa kỳ lạ. Khách hàng muốn trang mà họ xác thực để duy trì mở và trang / trang đích mới sau khi xác thực để mở trong một tab mới. Vâng, không phải ý tưởng của tôi về trải nghiệm người dùng tuyệt vời ... nhưng có vẻ hợp lý
Don Cheadle

@mmcrae. Hãy ngồi xuống và suy nghĩ, nghiêm túc. Tôi hứa với bạn bạn sẽ tìm thấy một "hành động người dùng" trong kịch bản bạn mô tả. Toàn bộ câu trả lời của tôi là bạn tạo cửa sổ bật lên khi bạn có hành động của người dùng - và sau đó điền nội dung đó vào sau. Gợi ý cho trường hợp của bạn: người dùng nhấn "xác thực" -> tạo cửa sổ bật lên (trống); bộ đếm thời gian đã hết hoặc phản hồi của máy chủ đã hoạt động trở lại hoặc bất cứ điều gì -> điền nội dung vào cửa sổ bật lên.
Swiss Mister

3
Mẹo hữu ích, nếu yêu cầu ajax không thành công, hãy gọi importantStuff.closeđể đóng tab mới và cung cấp và cảnh báo trong trang gốc.
Ngỗng

24

Ngoài bài đăng Swiss Mister, trong trường hợp của tôi, window.open đã được đưa ra bên trong một lời hứa, điều này đã bật trình chặn cửa sổ bật lên, giải pháp của tôi là: trong góc:

$scope.gotClick = function(){

  var myNewTab = browserService.openNewTab();
  someService.getUrl().then(
    function(res){
        browserService.updateTabLocation(res.url, myNewTab);

    }
  );
};

dịch vụ trình duyệt:

this.openNewTab = function(){
     var newTabWindow = $window.open();
     return newTabWindow;
}

this.updateTabLocation = function(tabLocation, tab) {
     if(!tabLocation){
       tab.close();
     }
     tab.location.href = tabLocation;
}

đây là cách bạn có thể mở một tab mới bằng cách sử dụng phản hồi lời hứa và không gọi trình chặn cửa sổ bật lên.


1
Điều này dẫn đến giải pháp của tôi! Nơi tôi đã tạo một biến chứa tab đã mở và sau đó điền url sau khi dữ liệu được tải. Cảm ơn. const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
jonas

1
Nếu bạn đã bật trình chặn cửa sổ bật lên thì điều này sẽ không khắc phục được sự cố với trình chặn cửa sổ bật lên ...
Alejandro Vales

Giải pháp @Alejandro Vales jonas sẽ chỉ hoạt động nếu mã sẽ chạy từ một sự kiện onClick hoặc bất kỳ tương tác người dùng nào. Khi bạn cố gắng mở một tab mới thông qua windows.open bên trong một lời hứa, hết thời gian, đăng ký ... trình duyệt nghĩ rằng đó là một thao tác trên người dùng, vì vậy giải pháp là tạo một thể hiện trước khi nhập lời hứa, bên trong bạn chỉ cần thay đổi the href like jonas đã làm
David

@David Cảm ơn bạn rất nhiều !!! Tôi đã không tình cờ nhìn thấy .thencâu trả lời sau đó và đó là lý do tại sao tôi đã rất bối rối: / SRY ...
Alejandro Vales

@David Điều này thật tuyệt! Hoạt động như một lá bùa. Nếu tôi có thể làm phiền bạn chỉ bằng một câu hỏi nữa - bạn có biết làm thế nào để nó hoạt động trong Edge không? Một cú huých vào một nguồn tài nguyên phù hợp sẽ giúp ích rất nhiều ...
dzenesiz

21

Như một thực tiễn tốt, tôi nghĩ rằng nên kiểm tra xem cửa sổ bật lên có bị chặn hay không và hãy hành động trong trường hợp. Bạn cần biết rằng window.open có giá trị trả về và giá trị đó có thể là null nếu hành động thất bại. Ví dụ: trong đoạn mã sau:

function pop(url,w,h) {
    n=window.open(url,'_blank','toolbar=0,location=0,directories=0,status=1,menubar=0,titlebar=0,scrollbars=1,resizable=1,width='+w+',height='+h);
    if(n==null) {
        return true;
    }
    return false;
}

nếu cửa sổ bật lên bị chặn, window.open sẽ trả về null. Vì vậy, hàm sẽ trả về false.

Ví dụ: hãy tưởng tượng gọi hàm này trực tiếp từ bất kỳ liên kết nào với target="_blank": nếu cửa sổ bật lên được mở thành công, việc trả về falsesẽ chặn hành động liên kết, nếu không thì cửa sổ bật lên bị chặn, việc trả về truesẽ cho phép hành vi mặc định (mở cửa sổ _blank mới) và tiếp tục .

<a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' >

Bằng cách này, bạn sẽ có một cửa sổ bật lên nếu nó hoạt động và cửa sổ _blank nếu không.

Nếu cửa sổ bật lên không mở, bạn có thể:

  • mở một cửa sổ trống như trong ví dụ và tiếp tục
  • mở một popup giả mạo (một iframe bên trong trang)
  • thông báo cho người dùng ("vui lòng cho phép cửa sổ bật lên cho trang web này")
  • mở một cửa sổ trống và sau đó thông báo cho người dùng, v.v.

Cảm ơn bạn. Đã làm việc!
Bcktr

8

từ API JavaScript oauth của Google:

http://code.google.com.vn/p/google-api-javascript-client/wiki/Authentication

Xem khu vực nơi nó đọc:

Thiết lập xác thực

Việc triển khai OAuth 2.0 của khách hàng sử dụng cửa sổ bật lên để nhắc người dùng đăng nhập và phê duyệt ứng dụng. Cuộc gọi đầu tiên đến gapi.auth. Mượtize có thể kích hoạt trình chặn cửa sổ bật lên, vì nó gián tiếp mở cửa sổ bật lên. Để ngăn chặn trình chặn cửa sổ bật lên kích hoạt các cuộc gọi auth, hãy gọi gapi.auth.init (gọi lại) khi máy khách tải. Cuộc gọi lại được cung cấp sẽ được thực thi khi thư viện sẵn sàng thực hiện các cuộc gọi auth.

Tôi đoán nó liên quan đến câu trả lời thực sự ở trên trong cách giải thích nếu có phản hồi ngay lập tức, nó sẽ không vấp phải báo động bật lên. "Gapi.auth.init" đang khiến nó xuất hiện ngay lập tức.

Ứng dụng thực tế

Tôi đã tạo một microservice xác thực nguồn mở bằng cách sử dụng hộ chiếu nút vào npm và các gói hộ chiếu khác nhau cho mỗi nhà cung cấp. Tôi đã sử dụng cách tiếp cận chuyển hướng tiêu chuẩn cho bên thứ 3 để cung cấp cho nó URL chuyển hướng để quay lại. Đây là chương trình để tôi có thể có các địa điểm khác nhau để chuyển hướng trở lại nếu đăng nhập / đăng ký và trên các trang cụ thể.

github.com/sebringj/athu

Passportjs.org


3

Tôi đã thử nhiều giải pháp, nhưng anh ấy là giải pháp duy nhất thực sự hiệu quả với tôi trong tất cả các trình duyệt

let newTab = window.open(); newTab.location.href = url;


2
Điều này chỉ không hoạt động đối với những người đã bật trình chặn cửa sổ bật lên
Alejandro Vales

urlgì nó không được chỉ định
shinriyo

Ví dụ: url @shinriyo là liên kết đến bất kỳ trang nào bạn muốn truy cập, ví dụhttp://example.com
pomobc

@AlejandroVales tôi đã bật trình chặn cửa sổ bật lên và nó hoạt động. Vấn đề là window.open()không thể mở cửa sổ mới theo chương trình và nếu chúng ta cần, câu trả lời đó là một trong những lựa chọn. Với newTabbiến chúng tôi thực hiện tham chiếu window.open()và sau này chúng tôi có thể gọi nó, chèn urlchúng tôi cần, trong trường hợp của tôi là một số blob và tab mới sẽ được mở bằng url đã nhập.
stanimirsp

0

Tôi không muốn tạo trang mới trừ khi gọi lại thành công, vì vậy tôi đã làm điều này để mô phỏng nhấp chuột của người dùng:

function submitAndRedirect {
  apiCall.then(({ redirect }) => {
      const a = document.createElement('a');
      a.href = redirect;
      a.target = '_blank';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
  });
}

3
không hoạt động với tôi trong Chrome 62. Popup (trang) bị chặn.
s.ermakovich

1
Có bạn đúng - tôi cũng thấy điều này không nhất quán. Tôi đã kết thúc việc thực hiện cuộc gọi api của mình một cách đồng bộ
user3479425

-8

Cách dễ nhất để thoát khỏi điều này là:

  1. Không sử dụng tài liệu.open ().
  2. Thay vào đó hãy sử dụng this.document.location.href = location; vị trí là url được tải

Ví dụ :

<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>

<div onclick="loadUrl('company_page.jsp')">Abc</div>

Điều này làm việc rất tốt cho tôi. Chúc mừng


2
Điều gì về để mở url trong tab mới?
3 quy tắc
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.