É possível detectar " inativo " " no JavaScript?
Meu caso de uso principal provavelmente seria pré-buscar ou pré-carregar o conteúdo.
Tempo ocioso: período de inatividade do usuário ou sem uso da CPU
É possível detectar " inativo " " no JavaScript?
Meu caso de uso principal provavelmente seria pré-buscar ou pré-carregar o conteúdo.
Tempo ocioso: período de inatividade do usuário ou sem uso da CPU
Respostas:
Aqui está um script simples usando JQuery que lida com eventos de remoção de teclado e pressionamento de tecla. Se o tempo expirar, a página será recarregada.
<script type="text/javascript">
var idleTime = 0;
$(document).ready(function () {
//Increment the idle time counter every minute.
var idleInterval = setInterval(timerIncrement, 60000); // 1 minute
//Zero the idle timer on mouse movement.
$(this).mousemove(function (e) {
idleTime = 0;
});
$(this).keypress(function (e) {
idleTime = 0;
});
});
function timerIncrement() {
idleTime = idleTime + 1;
if (idleTime > 19) { // 20 minutes
window.location.reload();
}
}
</script>
setInterval
, que é avaliada como JavaScript.
idleTime++;
vez deidleTime = idleTime + 1;
'mousemove keydown click'
usam cadeias de caracteres, como o uso de sinalizadores de bit ( Event.MOUSEMOVE | Event.KEYDOWN | Event.CLICK
), pois são muito mais rápidas que as operações de cadeia de caracteres. Mas você realmente quer fazer isso?
Sem usar o jQuery, apenas JavaScript baunilha:
var inactivityTime = function () {
var time;
window.onload = resetTimer;
// DOM Events
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
function logout() {
alert("You are now logged out.")
//location.href = 'logout.html'
}
function resetTimer() {
clearTimeout(time);
time = setTimeout(logout, 3000)
// 1000 milliseconds = 1 second
}
};
E inicie a função onde você precisar (por exemplo: onPageLoad).
window.onload = function() {
inactivityTime();
}
Você pode adicionar mais eventos DOM, se necessário. Os mais usados são:
document.onload = resetTimer;
document.onmousemove = resetTimer;
document.onmousedown = resetTimer; // touchscreen presses
document.ontouchstart = resetTimer;
document.onclick = resetTimer; // touchpad clicks
document.onkeypress = resetTimer;
document.addEventListener('scroll', resetTimer, true); // improved; see comments
Ou registre os eventos desejados usando uma matriz
window.addEventListener('load', resetTimer, true);
var events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
events.forEach(function(name) {
document.addEventListener(name, resetTimer, true);
});
Lista de eventos do DOM : http://www.w3schools.com/jsref/dom_obj_event.asp
Lembre-se de usar window
ou de document
acordo com suas necessidades. Aqui você pode ver as diferenças entre eles: Qual é a diferença entre janela, tela e documento em Javascript?
O código atualizado com @ frank-conijn e @daxchen aprimoram: window.onscroll
não será acionado se a rolagem estiver dentro de um elemento rolável, porque os eventos de rolagem não borbulham. window.addEventListener('scroll', resetTimer, true)
, o terceiro argumento informa ao ouvinte para capturar o evento durante a fase de captura em vez da fase de bolha.
document.onload = function () { inactivityTime(); }; document.onmousedown = function () { inactivityTime(); }; document.onkeypress = function () { inactivityTime(); }; document.ontouchstart = function () { inactivityTime(); };
Melhorando a resposta de Equiman:
function idleLogout() {
var t;
window.onload = resetTimer;
window.onmousemove = resetTimer;
window.onmousedown = resetTimer; // catches touchscreen presses as well
window.ontouchstart = resetTimer; // catches touchscreen swipes as well
window.onclick = resetTimer; // catches touchpad clicks as well
window.onkeypress = resetTimer;
window.addEventListener('scroll', resetTimer, true); // improved; see comments
function yourFunction() {
// your function for too long inactivity goes here
// e.g. window.location.href = 'logout.php';
}
function resetTimer() {
clearTimeout(t);
t = setTimeout(yourFunction, 10000); // time is in milliseconds
}
}
idleLogout();
.
Além das melhorias relacionadas à detecção de atividades e à mudança de document
para window
, esse script realmente chama a função, em vez de deixá-la ociosa.
Ele não captura o uso zero da CPU diretamente, mas isso é impossível, porque a execução de uma função causa o uso da CPU. E a inatividade do usuário acaba levando a zero uso da CPU; portanto, indiretamente, ele captura zero uso da CPU.
window.onscroll
não será acionado se a rolagem estiver dentro de um elemento rolável, porque os eventos de rolagem não borbulham. Usando window.addEventListener('scroll', resetTimer, true)
, o terceiro argumento diz ao ouvinte para o evento capturas durante capture
fase em vez de bubble
fase (IE> 8), veja esta resposta
document.onscroll
tem o mesmo problema, não dispara se a rolagem estiver dentro de um filho rolável?
addEventListener
vez de onscroll
.
Eu criei uma pequena lib que faz isso há um ano:
https://github.com/shawnmclean/Idle.js
Descrição:
Pequena biblioteca javascript para relatar a atividade do usuário no navegador (ausente, ocioso, sem olhar para a página da Web, em uma guia diferente, etc.). que é independente de outras bibliotecas javascript, como jquery.
Os usuários do Visual Studio podem obtê-lo no NuGet: PM> Install-Package Idle.js
Aqui está uma implementação aproximada do jQuery da ideia de tvanfosson:
$(document).ready(function(){
idleTime = 0;
//Increment the idle time counter every second.
var idleInterval = setInterval(timerIncrement, 1000);
function timerIncrement()
{
idleTime++;
if (idleTime > 2)
{
doPreload();
}
}
//Zero the idle timer on mouse movement.
$(this).mousemove(function(e){
idleTime = 0;
});
function doPreload()
{
//Preload images, etc.
}
})
setInterval
uma corda! Apenas dê uma função como uma variável!
setInterval()
avaliar a expressão no escopo global e, portanto, não encontrará a timerIncrement()
função que está dentro da função manipulador .ready. Esse é mais um motivo para NUNCA passar as strings setInterval()
. Basta passar uma referência de função real e você não terá esse problema porque eles são avaliados no escopo atual.
Semelhante à solução da Iconic acima (com evento personalizado jQuery) ...
// use jquery-idle-detect.js script below
$(window).on('idle:start', function(){
//start your prefetch etc here...
});
$(window).on('idle:stop', function(){
//stop your prefetch etc here...
});
//jquery-idle-detect.js
(function($,$w){
// expose configuration option
// idle is triggered when no events for 2 seconds
$.idleTimeout = 2000;
// currently in idle state
var idle = false;
// handle to idle timer for detection
var idleTimer = null;
//start idle timer and bind events on load (not dom-ready)
$w.on('load', function(){
startIdleTimer();
$w.on('focus resize mousemove keyup', startIdleTimer)
.on('blur',idleStart) //force idle when in a different tab/window
;
]);
function startIdleTimer() {
clearTimeout(idleTimer); //clear prior timer
if (idle) $w.trigger('idle:stop'); //if idle, send stop event
idle = false; //not idle
var timeout = ~~$.idleTimeout; // option to integer
if (timeout <= 100) timeout = 100; // min 100ms
if (timeout > 300000) timeout = 300000; // max 5 minutes
idleTimer = setTimeout(idleStart, timeout); //new timer
}
function idleStart() {
if (!idle) $w.trigger('idle:start');
idle = true;
}
}(window.jQuery, window.jQuery(window)))
Você pode fazer isso de forma mais elegante com sublinhado e jquery -
$('body').on("click mousemove keyup", _.debounce(function(){
// do preload here
}, 1200000)) // 20 minutes debounce
Minha resposta foi inspirada na resposta de vijay , mas é uma solução mais curta e geral que pensei em compartilhar para qualquer pessoa que pudesse ajudar.
(function () {
var minutes = true; // change to false if you'd rather use seconds
var interval = minutes ? 60000 : 1000;
var IDLE_TIMEOUT = 3; // 3 minutes in this example
var idleCounter = 0;
document.onmousemove = document.onkeypress = function () {
idleCounter = 0;
};
window.setInterval(function () {
if (++idleCounter >= IDLE_TIMEOUT) {
window.location.reload(); // or whatever you want to do
}
}, interval);
}());
Como está atualmente, esse código será executado imediatamente e recarregará sua página atual após 3 minutos sem nenhum movimento do mouse ou pressionamento de tecla.
Isso utiliza JavaScript simples e uma expressão de função chamada imediatamente para lidar com tempos limite inativos de maneira limpa e independente.
onclick
tarefa, pois provavelmente não é necessário além disso onmousemove
, mas obviamente qualquer um desses eventos acionados programaticamente continuará sendo redefinido idleCounter
. Não sei por que você simularia a interação do usuário em vez de apenas chamar uma função, mas se for algo que precisa fazer por algum motivo, essa resposta obviamente não funcionará para você, nem a maioria das outras respostas. Eu olhei para esta questão.
Sei que é uma pergunta relativamente antiga, mas tive o mesmo problema e encontrei uma solução muito boa.
Eu usei: jquery.idle e só precisava fazer:
$(document).idle({
onIdle: function(){
alert('You did nothing for 5 seconds');
},
idle: 5000
})
Veja a demonstração do JsFiddle .
(Apenas para informações: veja isso para rastreamento de eventos de back-end Leads load do navegador )
keepTracking
opção para false
. Se você deseja redefinir, você pode tentar reinicializar. Aqui está um exemplo modificado que seria
Todas as respostas anteriores têm um manipulador de ratoeiras sempre ativo. Se o manipulador for jQuery, o processamento adicional que o jQuery executa pode ser adicionado. Especialmente se o usuário estiver usando um mouse para jogos, podem ocorrer até 500 eventos por segundo.
Esta solução evita o manuseio de todos os eventos do mouse. Isso resulta em um pequeno erro de tempo, mas que você pode ajustar à sua necessidade.
function setIdleTimeout(millis, onIdle, onUnidle) {
var timeout = 0;
startTimer();
function startTimer() {
timeout = setTimeout(onExpires, millis);
document.addEventListener("mousemove", onActivity);
document.addEventListener("keydown", onActivity);
}
function onExpires() {
timeout = 0;
onIdle();
}
function onActivity() {
if (timeout) clearTimeout(timeout);
else onUnidle();
//since the mouse is moving, we turn off our event hooks for 1 second
document.removeEventListener("mousemove", onActivity);
document.removeEventListener("keydown", onActivity);
setTimeout(startTimer, 1000);
}
}
$(startTimer)
que equivale a $(document).ready(startTimer)
, garante que o DOM está pronto antes de ligar o mousemove e eventos keypress.
Você provavelmente poderia hackear algo ao detectar o movimento do mouse no corpo do formulário e atualizar uma variável global com a última hora do movimento. Você precisaria então ter um temporizador de intervalo em funcionamento que verifique periodicamente o último tempo de movimento e faça alguma coisa se já tiver sido suficientemente longo desde que o último movimento do mouse foi detectado.
Eu escrevi uma pequena classe ES6 para detectar atividades e acionar eventos em tempo limite ocioso. Ele cobre teclado, mouse e toque , pode ser ativado e desativado e possui uma API muito enxuta:
const timer = new IdleTimer(() => alert('idle for 1 minute'), 1000 * 60 * 1);
timer.activate();
Ele não depende do jQuery, embora seja necessário executá-lo no Babel para oferecer suporte a navegadores mais antigos.
https://gist.github.com/4547ef5718fd2d31e5cdcafef0208096
Posso liberá-lo como um pacote npm assim que receber algum feedback.
Se você estiver direcionando um navegador suportado (Chrome ou Firefox em dezembro de 2018), poderá experimentar o requestIdleCallback e incluir o shim requestIdleCallback para navegadores não suportados.
Experimente este código, ele funciona perfeitamente.
var IDLE_TIMEOUT = 10; //seconds
var _idleSecondsCounter = 0;
document.onclick = function () {
_idleSecondsCounter = 0;
};
document.onmousemove = function () {
_idleSecondsCounter = 0;
};
document.onkeypress = function () {
_idleSecondsCounter = 0;
};
window.setInterval(CheckIdleTime, 1000);
function CheckIdleTime() {
_idleSecondsCounter++;
var oPanel = document.getElementById("SecondsUntilExpire");
if (oPanel)
oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
if (_idleSecondsCounter >= IDLE_TIMEOUT) {
alert("Time expired!");
document.location.href = "SessionExpired.aspx";
}
}
<script type="text/javascript">
var idleTime = 0;
$(document).ready(function () {
//Increment the idle time counter every minute.
idleInterval = setInterval(timerIncrement, 60000); // 1 minute
//Zero the idle timer on mouse movement.
$('body').mousemove(function (e) {
//alert("mouse moved" + idleTime);
idleTime = 0;
});
$('body').keypress(function (e) {
//alert("keypressed" + idleTime);
idleTime = 0;
});
$('body').click(function() {
//alert("mouse moved" + idleTime);
idleTime = 0;
});
});
function timerIncrement() {
idleTime = idleTime + 1;
if (idleTime > 10) { // 10 minutes
window.location.assign("http://www.google.com");
}
}
</script>
Eu acho que esse código jquery é perfeito, apesar de copiado e modificado das respostas acima !! Não esqueça de incluir a biblioteca jquery no seu arquivo!
O problema com todas essas soluções, apesar de corretas, é impraticável ao levar em consideração o conjunto valioso de tempo limite da sessão, usando PHP, .NET ou no arquivo Application.cfc para desenvolvedores do Coldfusion. O tempo definido pela solução acima precisa sincronizar com o tempo limite da sessão no servidor. Se os dois não sincronizarem, você poderá encontrar problemas que apenas frustram e confundem seus usuários. Por exemplo, o tempo limite da sessão no servidor pode ser definido como 60 minutos, mas o usuário pode acreditar que está seguro, porque a captura de tempo ocioso do JavaScript aumentou a quantidade total de tempo que um usuário pode gastar em uma única página. O usuário pode ter passado algum tempo preenchendo um formulário longo e depois enviá-lo. O tempo limite da sessão pode ocorrer antes que o envio do formulário seja processado. Costumo dar aos meus usuários 180 minutos, e use o JavaScript para desconectar automaticamente o usuário. Essencialmente, usando parte do código acima, para criar um timer simples, mas sem a parte do evento de captura do mouse. Dessa maneira, meu horário do lado do cliente e do servidor é sincronizado perfeitamente. Não há confusão, se você mostrar o tempo para o usuário na sua interface do usuário, pois ele reduz. Sempre que uma nova página é acessada no CMS, a sessão do servidor e o timer JavaScript são redefinidos. Simples e elegante. Se um usuário permanecer em uma única página por mais de 180 minutos, acho que há algo errado com a página, em primeiro lugar. como reduz. Sempre que uma nova página é acessada no CMS, a sessão do servidor e o timer JavaScript são redefinidos. Simples e elegante. Se um usuário permanecer em uma única página por mais de 180 minutos, acho que há algo errado com a página, em primeiro lugar. como reduz. Sempre que uma nova página é acessada no CMS, a sessão do servidor e o timer JavaScript são redefinidos. Simples e elegante. Se um usuário permanecer em uma única página por mais de 180 minutos, acho que há algo errado com a página, em primeiro lugar.
JavaScript puro com tempo de redefinição e ligações adequadamente configurados via addEventListener
(function() {
var t,
timeout = 5000;
function resetTimer() {
console.log("reset: " + new Date().toLocaleString());
if (t) {
window.clearTimeout(t);
}
t = window.setTimeout(logout, timeout);
}
function logout() {
console.log("done: " + new Date().toLocaleString());
}
resetTimer();
//And bind the events to call `resetTimer()`
["click", "mousemove", "keypress"].forEach(function(name) {
console.log(name);
document.addEventListener(name, resetTimer);
});
}());
(Parcialmente inspirado na boa lógica central de Equiman, anteriormente neste tópico.)
sessionExpiration.js é leve, mas eficaz e personalizável. Uma vez implementado, use em apenas uma linha:
sessionExpiration(idleMinutes, warningMinutes, logoutUrl);
Este é um exemplo de como fica em ação, se você não alterar o CSS.
Eu escrevi um plugin jQuery simples que fará o que você está procurando.
https://github.com/afklondon/jquery.inactivity
$(document).inactivity( {
interval: 1000, // the timeout until the inactivity event fire [default: 3000]
mouse: true, // listen for mouse inactivity [default: true]
keyboard: false, // listen for keyboard inactivity [default: true]
touch: false, // listen for touch inactivity [default: true]
customEvents: "customEventName", // listen for custom events [default: ""]
triggerAll: true, // if set to false only the first "activity" event will be fired [default: false]
});
O script escutará o mouse, teclado, toque e outros eventos personalizados inativos (inativos) e acionará eventos globais de "atividade" e "inatividade".
Espero que isto ajude :)
Apenas alguns pensamentos, uma avenida ou duas para explorar.
É possível executar uma função a cada 10 segundos e verificar essa variável "counter"? Se isso for possível, você pode passar o mouse sobre a página, não é? Nesse caso, use o evento mouseover para redefinir a variável "counter". Se sua função for chamada e o contador estiver acima do intervalo que você pré-determina, faça sua ação.
Mais uma vez, apenas alguns pensamentos ... Espero que ajude.
Eu testei este arquivo de trabalho de código:
var timeout = null;
var timee = '4000'; // default time for session time out.
$(document).bind('click keyup mousemove', function(event) {
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
timeout = null;
console.log('Document Idle since '+timee+' ms');
alert("idle window");
}, timee);
});
Aqui está a melhor solução que encontrei: http://css-tricks.com/snippets/jquery/fire-event-when-user-is-idle/
Aqui está o JS:
idleTimer = null;
idleState = false;
idleWait = 2000;
(function ($) {
$(document).ready(function () {
$('*').bind('mousemove keydown scroll', function () {
clearTimeout(idleTimer);
if (idleState == true) {
// Reactivated event
$("body").append("<p>Welcome Back.</p>");
}
idleState = false;
idleTimer = setTimeout(function () {
// Idle Event
$("body").append("<p>You've been idle for " + idleWait/1000 + " seconds.</p>");
idleState = true; }, idleWait);
});
$("body").trigger("mousemove");
});
}) (jQuery)
Você pode usar a solução abaixo mencionada
var idleTime;
$(document).ready(function () {
reloadPage();
$('html').bind('mousemove click mouseup mousedown keydown keypress keyup submit change mouseenter scroll resize dblclick', function () {
clearTimeout(idleTime);
reloadPage();
});
});
function reloadPage() {
clearTimeout(idleTime);
idleTime = setTimeout(function () {
location.reload();
}, 3000);
}
Eu uso essa abordagem, já que você não precisa redefinir constantemente o horário em que um evento é disparado; em vez disso, apenas gravamos o horário, isso gera o ponto inicial ocioso.
function idle(WAIT_FOR_MINS, cb_isIdle) {
var self = this,
idle,
ms = (WAIT_FOR_MINS || 1) * 60000,
lastDigest = new Date(),
watch;
//document.onmousemove = digest;
document.onkeypress = digest;
document.onclick = digest;
function digest() {
lastDigest = new Date();
}
// 1000 milisec = 1 sec
watch = setInterval(function(){
if (new Date() - lastDigest > ms && cb_isIdel) {
clearInterval(watch);
cb_isIdle();
}
}, 1000*60);
},
Provavelmente, você pode detectar inatividade em sua página da web usando os truques de remoção de rato listados, mas isso não informa que o usuário não está em outra página em outra janela ou guia, ou que está no Word ou Photoshop, ou WOW e no momento não está visualizando sua página. Geralmente, eu apenas fazia a pré-busca e confiava nas multitarefas do cliente. Se você realmente precisar dessa funcionalidade, faça algo com um controle activex no Windows, mas é feio na melhor das hipóteses.
Aqui está um serviço AngularJS para realizar em Angular.
/* Tracks now long a user has been idle. secondsIdle can be polled
at any time to know how long user has been idle. */
fuelServices.factory('idleChecker',['$interval', function($interval){
var self = {
secondsIdle: 0,
init: function(){
$(document).mousemove(function (e) {
self.secondsIdle = 0;
});
$(document).keypress(function (e) {
self.secondsIdle = 0;
});
$interval(function(){
self.secondsIdle += 1;
}, 1000)
}
}
return self;
}]);
Lembre-se de que esse verificador inativo será executado em todas as rotas; portanto, ele deve ser inicializado no .run()
carregamento do aplicativo angular. Então você pode usar idleChecker.secondsIdle
dentro de cada rota.
myApp.run(['idleChecker',function(idleChecker){
idleChecker.init();
}]);
Debounce realmente uma ótima idéia! Aqui versão para projetos livres do jQuery:
const derivedLogout = createDerivedLogout(30);
derivedLogout(); // it could happen that user too idle)
window.addEventListener('click', derivedLogout, false);
window.addEventListener('mousemove', derivedLogout, false);
window.addEventListener('keyup', derivedLogout, false);
function createDerivedLogout (sessionTimeoutInMinutes) {
return _.debounce( () => {
window.location = this.logoutUrl;
}, sessionTimeoutInMinutes * 60 * 1000 )
}
Tão simples quanto possível, detecte quando o mouse se move apenas:
var idle = false;
document.querySelector('body').addEventListener('mousemove', function(e) {
if(idle!=false)idle = false;
});
var idleI = setInterval(function()
{
if(idle == 'inactive')
{
return;
}
if(idle == true)
{
idleFunction();
idle = 'inactive';
return;
}
idle = true;
}, 30000);// half the expected time, idle will trigger after 60s in this case.
function idleFuntion()
{
console.log('user is idle');
}
Bem, você pode anexar um evento de clique ou remoção do mouse ao corpo do documento que redefine um timer. Tenha uma função que você chama em intervalos de tempo que verifica se o cronômetro está acima de um tempo especificado (como 1000 milis) e inicia sua pré-carga.
Javascript não tem como saber o uso da CPU. Isso quebraria o javascript da sandbox executado dentro.
Fora isso, conectar os eventos onmouseover e onkeydown da página provavelmente funcionaria.
Você também pode definir o uso de setTimeout no evento onload para agendar uma função a ser chamada após um atraso.
// Call aFunction after 1 second
window.setTimeout(aFunction, 1000);