Phát hiện nếu tab trình duyệt có tiêu điểm


149

Có một cách đa trình duyệt đáng tin cậy để phát hiện ra rằng một tab có trọng tâm.

Kịch bản là chúng tôi có một ứng dụng thăm dò ý kiến ​​thường xuyên về giá cổ phiếu và nếu trang không tập trung, chúng tôi có thể dừng bỏ phiếu và tiết kiệm cho mọi người tiếng ồn giao thông, đặc biệt là khi mọi người là người hâm mộ mở một số tab với các danh mục đầu tư khác nhau.

window.onblurwindow.onfocusmột lựa chọn cho điều này?


Câu trả lời:


127

Có, window.onfocuswindow.onblurnên hoạt động cho kịch bản của bạn:

http://www.thefutureoftheweb.com/blog/detect-browser-window-f Focus


3
Khía cạnh onf Focusin / onf Focusout của điều này, và cũng là lưu ý về việc nói với người dùng mà bạn đã tạm dừng là những ghi chú thực sự tốt. Cảm ơn.
Fenton

7
Xin lưu ý rằng bạn không thể phân biệt giữa trang đang hoạt động hoặc không hoạt động khi tải trang theo cách này.
pimvdb

@SteveFenton - onfocuslà crossbrowser, trong đó các sự kiện bạn đã đề cập chỉ dành cho IE, tôi không thể hiểu tại sao điều này sẽ được coi là một ghi chú tốt của bạn ..
vsync

1
@vsync - đọc bài viết được liên kết, bạn sẽ thấy nó sử dụng cả 'onf Focusin' và 'onf Focus'.
Fenton

Bạn có thể ít nhất đề cập đến sự khác biệt giữa hai?
Lenar Hoyt

53

Chỉnh sửa quan trọng: Câu trả lời này đã lỗi thời. Kể từ khi viết nó, API khả năng hiển thị ( mdn , ví dụ , spec ) đã được giới thiệu. Đó là cách tốt hơn để giải quyết vấn đề này.


var focused = true;

window.onfocus = function() {
    focused = true;
};
window.onblur = function() {
    focused = false;
};

AFAIK, focusblurtất cả đều được hỗ trợ trên ... mọi thứ. (xem http://www.quirksmode.org/dom/events/index.html )


2
Chỉ cần lưu ý một chút, với tất cả các giải pháp này, bạn sẽ gặp rủi ro khi người dùng thay đổi tab trước khi javascript được tải đầy đủ, do đó gán giá trị sai cho tập trung. Không chắc chắn có một cách tốt xung quanh nó.
JayD3e

Các liên kết cập nhật chính xác là những gì tôi đang tìm kiếm. Cảm ơn đã thêm chúng!
webLacky3rdClass

Câu hỏi cụ thể là về việc phát hiện xem một trang có tập trung hay không, khác với việc phát hiện xem trang có hiển thị hay không. Nhiều trang có thể được hiển thị cùng một lúc (trong các cửa sổ khác nhau), trong khi chỉ có một trang có thể có tiêu điểm. Sử dụng bất kỳ kỹ thuật nào phù hợp với nhu cầu của bạn, nhưng biết sự khác biệt.
jaredjacobs

1
Đây là một giải pháp nguy hiểm vì nó có nguy cơ ghi đè một số người nghe sự kiện khác trong một ứng dụng lớn hơn. Thay vào đó, bạn nên làm theo câu trả lời này: stackoverflow.com/a/21935031/549503
mmmeff

51

Trong khi tìm kiếm về vấn đề này, tôi đã tìm thấy một khuyến nghị rằng nên sử dụng API hiển thị trang . Hầu hết các trình duyệt hiện đại đều hỗ trợ API này theo Tôi có thể sử dụng: http://caniuse.com/#feat=pagevisibility .

Đây là một ví dụ hoạt động (xuất phát từ đoạn trích này ):

$(document).ready(function() {
  var hidden, visibilityState, visibilityChange;

  if (typeof document.hidden !== "undefined") {
    hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
  }

  var document_hidden = document[hidden];

  document.addEventListener(visibilityChange, function() {
    if(document_hidden != document[hidden]) {
      if(document[hidden]) {
        // Document hidden
      } else {
        // Document shown
      }

      document_hidden = document[hidden];
    }
  });
});

Cập nhật: Ví dụ trên được sử dụng để có các thuộc tính tiền tố cho trình duyệt Gecko và WebKit, nhưng tôi đã loại bỏ việc triển khai đó vì các trình duyệt này hiện đang cung cấp API Hiển thị trang mà không có tiền tố trong một thời gian. Tôi đã giữ tiền tố cụ thể của Microsoft để duy trì khả năng tương thích với IE10.


Khi tiền tố của nhà cung cấp đi từ này, có lẽ tôi sẽ chuyển!
Fenton

Chỉ có vấn đề thực sự với điều này không phải là tiền tố của nhà cung cấp vì có khuyến nghị chính thức của W3C (ngày 29 tháng 10 năm 2013). Vấn đề trong một số trường hợp là API khả năng hiển thị trang được hỗ trợ trong IE10 và mới hơn. Nếu bạn cần hỗ trợ IE9, bạn nên tìm một cách tiếp cận khác
Ilija

Đây là cách chính xác để làm điều đó cho tất cả các trình duyệt hiện đại. +1
Ajedi32

Bạn có chắc chắn những tiền tố nhà cung cấp này thậm chí còn cần thiết? Theo MDN và CanIUse, chúng không cần thiết trên Chrome kể từ phiên bản 32 hoặc trên Firefox kể từ phiên bản 17 và chúng chưa bao giờ cần thiết trên IE.
Ajedi32

@ Ajedi32 Cảm ơn. Tôi sẽ cần thực hiện một số thử nghiệm và đào để xem những gì nó vẫn còn liên quan và những gì có thể bị bỏ lại ngay bây giờ.
Ilija

37

Ngạc nhiên khi thấy không ai nhắc đến document.hasFocus

if (document.hasFocus()) console.log('Tab is active')

MDN có nhiều thông tin hơn.


hoạt động với tôi (đã thử nghiệm trên Chrome và Firefox). Câu trả lời được chấp nhận (
onf Focus

Câu trả lời đúng một lần nữa ở dưới cùng. Cách để đi StackOverflow!
Tháng Mười Mười Một

thực sự, đây không phải là câu trả lời hoàn hảo sao? Có ai thấy nhược điểm nào không?
gaspar

2
Nhược điểm duy nhất của điều này là nếu bạn đang cố xác định xem tab có nằm trong tiêu điểm từ trong iframe hay không, thì nó sẽ thất bại trong trường hợp iframe được tải khi trang mẹ vẫn nằm ngoài tiêu điểm. Để bao quát điều đó cũng sẽ phải đi với api khả năng hiển thị trang.
Ivan

29

Có những người nên làm việc cho bạn. Bạn chỉ cần nhắc tôi về liên kết này, tôi đã bắt gặp khai thác những kỹ thuật đó. đọc thú vị


2
+1 - đó là một mẹo rất thông minh, tôi có thể tưởng tượng rằng đánh lừa rất nhiều người.
Fenton

2
Thật là một cuộc tấn công khéo léo và lệch lạc. Thú vị đọc rằng, cảm ơn.
Voo

4

Tôi sẽ làm theo cách này (Tham khảo http://www.w3.org/TR/page-visibility/ ):

    window.onload = function() {

        // check the visiblility of the page
        var hidden, visibilityState, visibilityChange;

        if (typeof document.hidden !== "undefined") {
            hidden = "hidden", visibilityChange = "visibilitychange", visibilityState = "visibilityState";
        }
        else if (typeof document.mozHidden !== "undefined") {
            hidden = "mozHidden", visibilityChange = "mozvisibilitychange", visibilityState = "mozVisibilityState";
        }
        else if (typeof document.msHidden !== "undefined") {
            hidden = "msHidden", visibilityChange = "msvisibilitychange", visibilityState = "msVisibilityState";
        }
        else if (typeof document.webkitHidden !== "undefined") {
            hidden = "webkitHidden", visibilityChange = "webkitvisibilitychange", visibilityState = "webkitVisibilityState";
        }


        if (typeof document.addEventListener === "undefined" || typeof hidden === "undefined") {
            // not supported
        }
        else {
            document.addEventListener(visibilityChange, function() {
                console.log("hidden: " + document[hidden]);
                console.log(document[visibilityState]);

                switch (document[visibilityState]) {
                case "visible":
                    // visible
                    break;
                case "hidden":
                    // hidden
                    break;
                }
            }, false);
        }

        if (document[visibilityState] === "visible") {
            // visible
        }

    };  

Bạn có thể giải thích câu trả lời này khác với câu trả lời được đưa ra bởi @Ilija không - có thể có một sự khác biệt, nhưng nó rất tinh tế - vì vậy một lời giải thích về nó là gì và tại sao nó nên khác biệt sẽ được đánh giá cao.
Fenton

2

Giải pháp chéo trình duyệt jQuery! Nguyên có sẵn tại GitHub

Thú vị và dễ sử dụng!

Plugin sau sẽ trải qua bài kiểm tra tiêu chuẩn của bạn cho các phiên bản khác nhau của IE, Chrome, Firefox, Safari, v.v. và thiết lập các phương thức khai báo của bạn theo đó. Nó cũng giải quyết các vấn đề như:

  • onblur | .blur / onf Focus | .f Focus " trùng lặp " các cuộc gọi
  • cửa sổ mất tập trung thông qua lựa chọn ứng dụng thay thế, như từ
    • Điều này có xu hướng không mong muốn đơn giản bởi vì, nếu bạn mở trang ngân hàng và sự kiện onblur sẽ bảo nó che dấu trang, sau đó nếu bạn mở máy tính, bạn không thể xem trang nữa!
  • Không kích hoạt khi tải trang

Sử dụng đơn giản như: Cuộn xuống để ' Chạy đoạn trích '

$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
});

//  OR Pass False boolean, and it will not trigger on load,
//  Instead, it will first trigger on first blur of current tab_window
$.winFocus(function(event, isVisible) {
    console.log("Combo\t\t", event, isVisible);
}, false);

//  OR Establish an object having methods "blur" & "focus", and/or "blurFocus"
//  (yes, you can set all 3, tho blurFocus is the only one with an 'isVisible' param)
$.winFocus({
    blur: function(event) {
        console.log("Blur\t\t", event);
    },
    focus: function(event) {
        console.log("Focus\t\t", event);
    }
});

//  OR First method becoms a "blur", second method becoms "focus"!
$.winFocus(function(event) {
    console.log("Blur\t\t", event);
},
function(event) {
    console.log("Focus\t\t", event);
});

/*    Begin Plugin    */
;;(function($){$.winFocus||($.extend({winFocus:function(){var a=!0,b=[];$(document).data("winFocus")||$(document).data("winFocus",$.winFocus.init());for(x in arguments)"object"==typeof arguments[x]?(arguments[x].blur&&$.winFocus.methods.blur.push(arguments[x].blur),arguments[x].focus&&$.winFocus.methods.focus.push(arguments[x].focus),arguments[x].blurFocus&&$.winFocus.methods.blurFocus.push(arguments[x].blurFocus),arguments[x].initRun&&(a=arguments[x].initRun)):"function"==typeof arguments[x]?b.push(arguments[x]):
"boolean"==typeof arguments[x]&&(a=arguments[x]);b&&(1==b.length?$.winFocus.methods.blurFocus.push(b[0]):($.winFocus.methods.blur.push(b[0]),$.winFocus.methods.focus.push(b[1])));if(a)$.winFocus.methods.onChange()}}),$.winFocus.init=function(){$.winFocus.props.hidden in document?document.addEventListener("visibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="mozHidden")in document?document.addEventListener("mozvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden=
"webkitHidden")in document?document.addEventListener("webkitvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="msHidden")in document?document.addEventListener("msvisibilitychange",$.winFocus.methods.onChange):($.winFocus.props.hidden="onfocusin")in document?document.onfocusin=document.onfocusout=$.winFocus.methods.onChange:window.onpageshow=window.onpagehide=window.onfocus=window.onblur=$.winFocus.methods.onChange;return $.winFocus},$.winFocus.methods={blurFocus:[],blur:[],focus:[],
exeCB:function(a){$.winFocus.methods.blurFocus&&$.each($.winFocus.methods.blurFocus,function(b,c){this.apply($.winFocus,[a,!a.hidden])});a.hidden&&$.winFocus.methods.blur&&$.each($.winFocus.methods.blur,function(b,c){this.apply($.winFocus,[a])});!a.hidden&&$.winFocus.methods.focus&&$.each($.winFocus.methods.focus,function(b,c){this.apply($.winFocus,[a])})},onChange:function(a){var b={focus:!1,focusin:!1,pageshow:!1,blur:!0,focusout:!0,pagehide:!0};if(a=a||window.event)a.hidden=a.type in b?b[a.type]:
document[$.winFocus.props.hidden],$(window).data("visible",!a.hidden),$.winFocus.methods.exeCB(a);else try{$.winFocus.methods.onChange.call(document,new Event("visibilitychange"))}catch(c){}}},$.winFocus.props={hidden:"hidden"})})(jQuery);
/*    End Plugin      */

// Simple example
$(function() {
	$.winFocus(function(event, isVisible) {
		$('td tbody').empty();
		$.each(event, function(i) {
			$('td tbody').append(
				$('<tr />').append(
					$('<th />', { text: i }),
					$('<td />', { text: this.toString() })
				)
			)
		});
		if (isVisible) 
			$("#isVisible").stop().delay(100).fadeOut('fast', function(e) {
				$('body').addClass('visible');
				$(this).stop().text('TRUE').fadeIn('slow');
			});
		else {
			$('body').removeClass('visible');
			$("#isVisible").text('FALSE');
		}
	});
})
body { background: #AAF; }
table { width: 100%; }
table table { border-collapse: collapse; margin: 0 auto; width: auto; }
tbody > tr > th { text-align: right; }
td { width: 50%; }
th, td { padding: .1em .5em; }
td th, td td { border: 1px solid; }
.visible { background: #FFA; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h3>See Console for Event Object Returned</h3>
<table>
    <tr>
        <th><p>Is Visible?</p></th>
        <td><p id="isVisible">TRUE</p></td>
    </tr>
    <tr>
        <td colspan="2">
            <table>
                <thead>
                    <tr>
                        <th colspan="2">Event Data <span style="font-size: .8em;">{ See Console for More Details }</span></th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </td>
    </tr>
</table>


Bạn nên đặt mã không được thu nhỏ cho plugin.
Patrick Desjardins

@PatrickDesjardins vâng. Kế hoạch thực hiện vào cuối tuần này cùng với những thứ khác. TÔI? Làm một ý chính cho một loạt các công cụ tôi có. Jdmckinstry tại github. Sẽ thêm liên kết đến các câu trả lời cũ như thế này khi tôi thêm chúng vào ý chính
SpYk3HH

Điều gì xảy ra nếu tôi muốn trang bị mất tiêu điểm, khi tôi chuyển sang một ứng dụng khác, như "Word" hoặc "Máy tính"?
Benas

@Benas có thể sai, nhưng tôi tin rằng đó là chức năng cơ bản của rất cơ bản jQuery(window).blur/focus, điều mà nhiều người không mong muốn, do đó, một trong những lý do tôi tạo ra plugin này. Plugin có nghĩa là giúp cung cấp những gì jQuery chưa có
SpYk3HH
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.