ตรวจสอบว่าแท็บเบราว์เซอร์โฟกัสหรือไม่


149

มีวิธีข้ามเบราว์เซอร์ที่เชื่อถือได้ในการตรวจสอบว่าแท็บมีโฟกัสหรือไม่

สถานการณ์คือเรามีแอปพลิเคชันที่สำรวจความคิดเห็นเป็นประจำสำหรับราคาหุ้นและหากหน้าเว็บไม่ได้ให้ความสำคัญเราสามารถหยุดการสำรวจและบันทึกเสียงการจราจรทุกคนโดยเฉพาะอย่างยิ่งเมื่อผู้คนเป็นแฟนของการเปิดแท็บต่างๆ

คือwindow.onblurและwindow.onfocusตัวเลือกสำหรับการนี้อยู่แล้ว?


คำตอบ:


127

ใช่window.onfocusและwindow.onblurควรใช้งานได้กับสถานการณ์ของคุณ:

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


3
ด้าน onfocusin / onfocusout ของสิ่งนี้และหมายเหตุเกี่ยวกับการบอกผู้ใช้ที่คุณหยุดไว้ชั่วคราวเป็นโน้ตที่ดีจริงๆ ขอบคุณ
เฟนตัน

7
โปรดทราบว่าคุณไม่สามารถแยกแยะระหว่างหน้าที่กำลังใช้งานหรือไม่ทำงานเมื่อโหลดหน้าเว็บด้วยวิธีนี้
pimvdb

@SteveFenton - onfocusเป็น crossbrowser ที่กิจกรรมที่คุณกล่าวถึงเป็นแบบ IE เท่านั้นฉันไม่เห็นว่าทำไมสิ่งนี้ถึงได้รับการพิจารณาเป็นอย่างดีจากคุณ ..
vsync

1
@vsync - อ่านบทความที่เชื่อมโยงคุณจะเห็นว่ามันใช้ทั้ง 'onfocusin' และ 'onfocus'
เฟนตัน

อย่างน้อยคุณจะพูดถึงความแตกต่างระหว่างทั้งสองหรือไม่
Lenar Hoyt

53

การแก้ไขที่สำคัญ:คำตอบนี้ล้าสมัยแล้ว ตั้งแต่การเขียนมันทัศนวิสัย API ( MDN ,ตัวอย่าง ,สเปค ) ได้รับการแนะนำ มันเป็นวิธีที่ดีกว่าในการแก้ปัญหานี้


var focused = true;

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

AFAIK focusและblurทุกอย่างรองรับ ... ทุกอย่าง (ดูhttp://www.quirksmode.org/dom/events/index.html )


2
ทราบเพียงเล็กน้อยด้วยโซลูชันเหล่านี้ทั้งหมดคุณจะเสี่ยงต่อการเปลี่ยนแท็บผู้ใช้ก่อนที่จาวาสคริปต์จะถูกโหลดจนเต็มดังนั้นจึงกำหนดค่าผิดให้เน้น ไม่แน่ใจว่ามีวิธีที่ดีรอบ ๆ มัน
JayD3e

ลิงก์อัปเดตเป็นสิ่งที่ฉันต้องการอย่างแน่นอน ขอบคุณที่เพิ่มพวกเขา!
webLacky3rdClass

คำถามนี้เกี่ยวกับการตรวจสอบว่าหน้าเว็บมีจุดโฟกัสหรือไม่ซึ่งแตกต่างจากการตรวจสอบว่าหน้านั้นสามารถมองเห็นได้หรือไม่ สามารถมองเห็นได้หลายหน้าในเวลาเดียวกัน (ในหน้าต่างที่แตกต่างกัน) ในขณะที่มีเพียงหน้าเดียวเท่านั้นที่สามารถโฟกัสได้ ใช้เทคนิคใดก็ตามที่เหมาะกับความต้องการของคุณ แต่ทราบความแตกต่าง
jaredjacobs

1
นี่เป็นวิธีที่อันตรายเพราะจะเสี่ยงต่อการแทนที่ผู้ฟังเหตุการณ์อื่นในแอปพลิเคชันขนาดใหญ่ คุณควรทำตามคำตอบนี้: stackoverflow.com/a/21935031/549503
mmmeff

51

ในขณะที่ค้นหาเกี่ยวกับปัญหานี้ฉันพบข้อเสนอแนะที่ควรใช้Page Visibility API เบราว์เซอร์ที่ทันสมัยที่สุดสนับสนุน API นี้ตามที่ฉันสามารถใช้: http://caniuse.com/#feat=pagevisibility

นี่คือตัวอย่างการทำงาน (มาจากตัวอย่างนี้ ):

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

อัปเดต:ตัวอย่างข้างต้นเคยมีคุณสมบัตินำหน้าสำหรับเบราว์เซอร์ Gecko และ WebKit แต่ฉันลบการติดตั้งนั้นเนื่องจากเบราว์เซอร์เหล่านี้เสนอ API การแสดงผลหน้าเว็บโดยไม่ต้องใช้คำนำหน้าในขณะนี้ ฉันเก็บคำนำหน้าเฉพาะของ Microsoft ไว้เพื่อให้สามารถทำงานร่วมกับ IE10 ได้


เมื่อผู้ขายนำหน้าจากนี้ฉันจะเปลี่ยน!
เฟนตัน

ปัญหาที่แท้จริงของเรื่องนี้ไม่ใช่คำนำหน้าผู้ขายเพราะมีคำแนะนำ W3C อย่างเป็นทางการ (ลงวันที่ 29 ตุลาคม 2013) มีปัญหาในบางกรณีคือ API การแสดงผลหน้าเว็บได้รับการสนับสนุนใน IE10 และใหม่กว่า หากคุณต้องการสนับสนุน IE9 คุณควรมองหาวิธีอื่น ...
Ilija

นี่เป็นวิธีที่ถูกต้องสำหรับเบราว์เซอร์สมัยใหม่ทั้งหมด +1
Ajedi32

คุณแน่ใจหรือไม่ว่ารหัสนำหน้าของผู้ขายเหล่านี้จำเป็นด้วยซ้ำ ตาม MDN และ CanIUse พวกเขาไม่จำเป็นต้องใช้ Chrome ตั้งแต่รุ่น 32 หรือ Firefox ตั้งแต่รุ่น 17 และพวกเขาไม่เคยจำเป็นบน IE
Ajedi32

@ Ajedi32 ขอบคุณ ฉันจะต้องทำการทดสอบและขุดเพื่อดูว่ามันยังเกี่ยวข้องและสิ่งที่สามารถออกตอนนี้
Ilija

37

น่าแปลกใจที่ไม่มีใครพูดถึง document.hasFocus

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

MDN มีข้อมูลเพิ่มเติม


ใช้งานได้สำหรับฉัน (ทดสอบบน Chrome และ Firefox) คำตอบที่ยอมรับ (onfocus / onblur) ไม่ทำงาน
harmv

คำตอบที่ถูกต้องอีกครั้งที่ด้านล่างมาก วิธีที่จะไป StackOverflow!
October Eleven

จริง ๆ นี่ไม่ใช่คำตอบที่สมบูรณ์แบบใช่ไหม ไม่มีใครเห็นข้อเสียใด ๆ ?
gaspar

2
ข้อเสียเพียงอย่างเดียวคือถ้าคุณพยายามตรวจสอบว่าแท็บอยู่ในโฟกัสจากใน iframe แล้วมันจะล้มเหลวในกรณีที่โหลด iframe เมื่อเพจระดับบนยังคงอยู่นอกโฟกัส เพื่อให้ครอบคลุมเช่นกันคุณจะต้องไปกับ API การแสดงผลหน้า
อีวาน

29

ใช่เหล่านั้นควรจะทำงานให้คุณ คุณเพิ่งเตือนฉันเกี่ยวกับลิงค์นี้ที่ฉันเจอซึ่งใช้ประโยชน์จากเทคนิคเหล่านั้น อ่านที่น่าสนใจ


2
+1 - นั่นเป็นเคล็ดลับที่ฉลาดมากฉันสามารถจินตนาการได้ว่าหลอกผู้คนจำนวนมาก
เฟนตัน

2
ช่างเป็นการโจมตีที่ฉลาดและคดเคี้ยว อ่านแล้วน่าสนใจขอบคุณ
Voo

4

ฉันจะทำเช่นนี้ (อ้างอิง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
        }

    };  

คุณช่วยอธิบายได้อย่างไรว่าคำตอบนี้แตกต่างจากคำตอบที่ @Ilija - อาจมีความแตกต่าง แต่ก็ละเอียด - ดังนั้นคำอธิบายว่ามันคืออะไรและทำไมมันควรจะแตกต่างกัน
เฟนตัน

2

Cross jQuery Solution! ดิบมีให้ที่GitHub

สนุกและใช้งานง่าย!

ปลั๊กอินต่อไปนี้จะผ่านการทดสอบมาตรฐานของคุณสำหรับ IE รุ่นต่างๆ, Chrome, Firefox, Safari และอื่น ๆ และสร้างวิธีการประกาศของคุณตามนั้น นอกจากนี้ยังเกี่ยวข้องกับปัญหาต่าง ๆ เช่น:

  • onblur | .blur / onfocus | .focus " ซ้ำ " การโทร
  • หน้าต่างสูญเสียโฟกัสผ่านการเลือกแอปอื่นเช่นคำ
    • สิ่งนี้มีแนวโน้มที่จะเป็นที่ไม่พึงประสงค์เพียงเพราะถ้าคุณเปิดหน้าธนาคารและมีเหตุการณ์onblurบอกให้ปิดบังหน้าแล้วถ้าคุณเปิดเครื่องคิดเลขคุณจะไม่เห็นหน้านั้นอีกต่อไป!
  • ไม่เรียกใช้การโหลดหน้าเว็บ

ใช้ง่ายเหมือน: เลื่อนลงไปที่ ' เรียกใช้ตัวอย่าง '

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


คุณควรวางโค้ดที่ไม่ย่อเล็กสุดสำหรับปลั๊กอิน
Patrick Desjardins

@PatrickDesjardins ใช่ วางแผนที่จะทำสุดสัปดาห์นี้พร้อมกับสิ่งอื่น ๆ ผม? ทำส่วนสำคัญสำหรับสิ่งที่ฉันมี Jdmckinstry ที่ github จะเพิ่มลิงก์ไปยังคำตอบเก่า ๆ เช่นนี้เมื่อฉันเพิ่มให้กับส่วนสำคัญ
SpYk3HH

จะทำอย่างไรถ้าฉันต้องการให้เพจสูญเสียการโฟกัสเมื่อฉันเปลี่ยนไปใช้แอปอื่นเช่น "Word" หรือ "เครื่องคิดเลข"
Benas

@Benas อาจจะผิด แต่ฉันเชื่อว่าเป็นฟังก์ชั่นพื้นฐานของพื้นฐานมากjQuery(window).blur/focusซึ่งไม่พึงประสงค์จากหลาย ๆ คนดังนั้นหนึ่งในเหตุผลที่ฉันทำปลั๊กอินนี้ ปลั๊กอินมีไว้เพื่อช่วยให้สิ่งที่ jQuery ยังไม่มีอยู่
SpYk3HH
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.