Erkennen, ob die Registerkarte Browser den Fokus hat


149

Gibt es eine zuverlässige browserübergreifende Methode, um festzustellen, ob eine Registerkarte den Fokus hat?

Das Szenario ist, dass wir eine Anwendung haben, die regelmäßig nach Aktienkursen fragt. Wenn die Seite keinen Fokus hat, können wir die Umfrage stoppen und allen den Verkehrslärm ersparen, insbesondere da die Leute gerne mehrere Registerkarten mit unterschiedlichen Portfolios öffnen.

Ist window.onblurund window.onfocuseine Option dafür?


Antworten:


127

Ja, window.onfocusund window.onblursollte für Ihr Szenario funktionieren:

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


3
Der Onfocusin / Onfocusout-Aspekt und auch der Hinweis, dem Benutzer mitzuteilen, dass Sie angehalten haben, sind wirklich gute Hinweise. Vielen Dank.
Fenton

7
Bitte beachten Sie, dass Sie auf diese Weise nicht unterscheiden können, ob die Seite beim Laden der Seite aktiv oder inaktiv ist.
Pimvdb

@SteveFenton - onfocusist Crossbrowser, wo die Ereignisse, die Sie erwähnt haben, nur IE sind. Ich kann nicht sehen, warum dies von Ihnen als eine gute Notiz angesehen wird.
vsync

1
@vsync - Lesen Sie den verlinkten Artikel. Sie werden sehen, dass sowohl 'onfocusin' als auch 'onfocus' verwendet werden.
Fenton

Könnten Sie zumindest den Unterschied zwischen den beiden erwähnen?
Lenar Hoyt

53

Wichtige Änderung: Diese Antwort ist veraltet. Seit dem Schreiben wurde die Sichtbarkeits-API ( mdn , Beispiel , spec ) eingeführt. Dies ist der bessere Weg, um dieses Problem zu lösen.


var focused = true;

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

AFAIK, focusund blurwerden alle auf ... alles unterstützt. (siehe http://www.quirksmode.org/dom/events/index.html )


2
Nur eine kleine Anmerkung: Bei all diesen Lösungen besteht die Gefahr, dass der Benutzer die Registerkarten wechselt, bevor das Javascript vollständig geladen ist, und so fokussiert den falschen Wert zuweist. Ich bin mir nicht sicher, ob es einen guten Weg gibt.
JayD3e

Die Update-Links sind genau das, wonach ich gesucht habe. Danke, dass du sie hinzugefügt hast!
webLacky3rdClass

Bei der Frage geht es speziell darum, festzustellen, ob eine Seite einen Fokus hat, was sich von der Erkennung unterscheidet, ob die Seite sichtbar ist. Es können mehrere Seiten gleichzeitig sichtbar sein (in verschiedenen Fenstern), während nur eine den Fokus haben kann. Verwenden Sie die Technik, die Ihren Anforderungen entspricht, kennen Sie jedoch den Unterschied.
Jaredjacobs

1
Dies ist eine gefährliche Lösung, da die Gefahr besteht, dass ein anderer Ereignis-Listener in einer größeren Anwendung überschrieben wird. Sie sollten stattdessen dieser Antwort folgen: stackoverflow.com/a/21935031/549503
mmmeff

51

Bei der Suche nach diesem Problem habe ich eine Empfehlung gefunden, die Page Visibility API zu verwenden. Die meisten modernen Browser unterstützen diese API gemäß Can I Use: http://caniuse.com/#feat=pagevisibility .

Hier ist ein Arbeitsbeispiel (abgeleitet von diesem Snippet ):

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

Update: Das obige Beispiel hatte früher Präfixeigenschaften für Gecko- und WebKit-Browser, aber ich habe diese Implementierung entfernt, da diese Browser seit einiger Zeit die Page Visibility API ohne Präfix anbieten. Ich habe das Microsoft-spezifische Präfix beibehalten, um mit IE10 kompatibel zu bleiben.


Wenn die Herstellerpräfixe davon abweichen, werde ich wahrscheinlich wechseln!
Fenton

Das einzige wirkliche Problem dabei sind keine Herstellerpräfixe, da es eine offizielle W3C-Empfehlung gibt (vom 29. Oktober 2013). In einigen Fällen ist das Problem, dass die API für die Sichtbarkeit von Seiten in IE10 und höher unterstützt wird. Wenn Sie IE9 unterstützen müssen, sollten Sie nach einem anderen Ansatz suchen…
Ilija

Dies ist der richtige Weg für alle modernen Browser. +1
Ajedi32

Sind Sie sicher, dass diese Herstellerpräfixe überhaupt erforderlich sind? Laut MDN und CanIUse waren sie in Chrome seit Version 32 oder in Firefox seit Version 17 nicht mehr erforderlich, und sie waren im IE nie erforderlich.
Ajedi32

@ Ajedi32 Danke. Ich muss einige Tests durchführen und graben, um zu sehen, was noch relevant ist und was jetzt weggelassen werden kann.
Ilija

37

Überraschend zu sehen, dass niemand erwähnt wurde document.hasFocus

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

MDN hat weitere Informationen.


funktioniert bei mir (getestet auf Chrome und Firefox). Die akzeptierte Antwort (onfocus / onblur) hat nicht funktioniert
harmv

Die richtige Antwort noch einmal ganz unten. Weiter so StackOverflow!
11. Oktober

Ist das nicht die perfekte Antwort? sieht jemand einen Nachteil?
Gaspar

2
Der einzige Nachteil dabei ist, dass, wenn Sie versuchen, innerhalb eines Iframes festzustellen, ob die Registerkarte im Fokus ist, dies fehlschlägt, wenn der Iframe geladen wurde, als die übergeordnete Seite noch unscharf war. Um dies ebenfalls abzudecken, müssen Sie die API für die Sichtbarkeit der Seite verwenden.
Ivan

29

Ja, die sollten für dich funktionieren. Sie haben mich nur an diesen Link erinnert, auf den ich gestoßen bin und der diese Techniken ausnutzt. interessante Lektüre


2
+1 - das ist ein sehr kluger Trick, ich könnte mir vorstellen, dass das viele Leute zum Narren hält.
Fenton

2
Was für ein genialer und hinterhältiger Angriff. Interessant zu lesen, danke.
Voo

4

Ich würde es so machen (Referenz 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
        }

    };  

Können Sie erklären, wie sich diese Antwort von der Antwort von @Ilija unterscheidet - es mag einen Unterschied geben, aber er ist subtil -, daher wäre eine Erklärung, was es ist und warum es anders sein sollte, wünschenswert.
Fenton

2

Browserübergreifende jQuery-Lösung! Raw bei GitHub erhältlich

Spaß und einfach zu bedienen!

Das folgende Plugin durchläuft Ihren Standardtest für verschiedene Versionen von IE, Chrome, Firefox, Safari usw. und legt Ihre deklarierten Methoden entsprechend fest. Es befasst sich auch mit Themen wie:

  • onblur | .blur / onfocus | .focus " doppelte " Aufrufe
  • Fenster verliert den Fokus durch Auswahl einer alternativen App wie Word
    • Dies ist in der Regel unerwünscht, da Sie die Seite nicht mehr sehen können , wenn Sie eine Bank-Seite geöffnet haben und das Ereignis " Unschärfe" die Seite maskieren soll. Wenn Sie den Taschenrechner öffnen, können Sie die Seite nicht mehr sehen!
  • Wird beim Laden der Seite nicht ausgelöst

Die Verwendung ist so einfach wie: Scrollen Sie nach unten zu " Snippet ausführen ".

$.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>


Sie sollten den Code für das Plugin nicht minimiert setzen.
Patrick Desjardins

@PatrickDesjardins ja. Planen Sie dieses Wochenende zusammen mit anderen Dingen. ICH? Machen Sie einen Kern für ein paar Sachen, die ich habe. Jdmckinstry bei Github. Fügt Links zu alten Antworten wie diesen hinzu, sobald ich sie zu gist hinzufüge
SpYk3HH

Was ist, wenn ich möchte, dass die Seite den Fokus verliert, wenn ich zu einer anderen App wie "Word" oder "Calculator" wechsle?
Benas

@Benas Könnte falsch sein, aber ich glaube, das ist die Basisfunktionalität der sehr grundlegenden jQuery(window).blur/focus, die von vielen unerwünscht war, daher einer der Gründe, warum ich dieses Plugin gemacht habe. Das Plugin soll helfen, das bereitzustellen, was jQuery noch nicht getan hat
SpYk3HH
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.