problema Lag com foco jQuery () e blur () eventos
-
08-07-2019 - |
Pergunta
Eu estou tentando criar um menu de navegação que usa alguns jQuery. Eu queria que os usuários de teclado para ser capaz de ter a mesma experiência que os usuários de mouse, por isso estou duplicar a funcionalidade encontrada no meu manipulador de eventos hover()
em meus focus()
e eventos blur()
manipuladores. Por alguma razão, isso está causando atraso perceptível no Firefox e IE quando o usuário clica em um link, o que não ocorre quando o código focus()
e blur()
é retirado. Como eu posso ir sobre acelerando isso? Eu fiz o máximo otimização do meu conhecimento javascript limitado permitirá, mas eu não vi nenhum "aceleração", por isso estou pensando que pode estar relacionado com a forma como estes navegadores manipular os eventos.
Existe alguma coisa importante que eu estou com vista? Ou existem formas alternativas para manter a acessibilidade para usuários de teclado, enquanto não usando estes eventos?
var statePad=0;
function stateChanger(ourStatePad) {
//the purpose of this function is to translate the current state of the menu into a different graphical representation of the menu state.
var tempVar=ouStatePad;
var tempArray = new Array;
tempArray[5]=0;
for (var x=0;x < 5;x++) {
tempArray[x]=tempVar % 10;
tempVar=(tempVar-tempArray[x])/10;
}
for (var arrayIndex=4;arrayIndex>=0;arrayIndex--) {
//Calculate the proper position in our CSS sprite, based on the each link's state, as well as it's neighbors'.
$(".block").eq(4 - arrayIndex)
.css(
"background-position",
//x-position
((4 - arrayIndex) * -100) + "px " +
//y-position
(tempArray[arrayIndex] + ((3 * tempArray[(arrayIndex) + 1]) * -30))) + "px";
}
}
function hoverState(index,sign) {
var placeholder=Math.pow(10,4-index);
if (statePad != placeholder*2)
statePad += (placeholder * sign);
stateChanger(statePad);
}
.click(function() {
var index=$("#navbar a").index(this);
statePad=Math.pow(10,(4-index))*2;
stateChanger(statePad);
$(".active").removeClass("active");
$(this).addClass("active");
})
.hover(
function () {
hoverState($("#navbar a").index(this),1);
},
function () {
hoverState($("#navbar a").index(this),-1);
});
$("#navbar a").focus(
function() {
hoverState($("#navbar a").index(this),1);
}
);
$("#navbar a").blur(
function() {
hoverState($("#navbar a").index(this),-1);
}
);
});
Você pode verificá-la aqui
Solução 2
Eu resolvi isto por acidente completo, mais ou menos. Eu percebi que o meu problema não era realmente o lag, que era apenas um sintoma de um "conflito de eventos".
O problema, tanto quanto eu posso dizer é que focus()
é desencadeada quer por tabulação até um link ou um mousedown()
em um elemento que pode receber foco. Então, cada vez que um link é clicado, está ficando foco. Mas, um evento click()
não está completo até que o mouse é liberado. Assim, o efeito que eu estava vendo no Firefox e IE foi o resultado de um ligeiro atraso entre mousedown()
e mouseup()
. Eu tentei apenas trocar o tratamento de eventos .click()
no meu código para mousedown()
, e uma vez que é apenas um único evento que eu estava olhando para fora para eu decidi integrar isso em minha função hoverState (). Eu acabei com isso:
function hoverState(e) {
var index = $(e.target.parentNode).prevAll().length;
if (e.type == 'mousedown') {
statePad=Math.pow(10,(4-index))*2;
$(".active").removeClass('active');
$("#"+ e.target.id).addClass('active');
}
else {
var sign = (e.type === 'mouseenter' ||
e.type === 'focus')? 1 : -1;
var placeholder=Math.pow(10,4-index);
if (statePad != placeholder*2)
statePad += (placeholder * sign);
$('h1').text(statePad + " " + e.type);
}
stateChanger(statePad);
}
$("#navbar a").bind("mouseenter mouseleave focus blur mousedown", hoverState);
No entanto, isso causou algum comportamento bizarro que ferrou a variável statePad. I revertido para o código que Russ Cam forneceu-me, e começou a repensar as coisas. Eu tentei sair na Opera, que eu ainda não tinha feito, e funcionou muito bem. Eu tentei-o no Safari e Chrome, e eles funcionou bem, como de costume. Eu tentei no Firefox, apenas tentando obter uma alça sobre o que o torna diferente, e ... ele estava trabalhando!
Eu olhei para o meu código, e verifica-se que eu ainda estava ligando a função hoverState ao evento mousedown()
. Eu não sei exatamente por que isso funciona, mas ele faz. Ele corrige o problema no IE, também. Strangle, faz com que um novo problema no Chrome, é tão pequena que eu não estou indo para se preocupar.
Eu não acho que eu teria sido capaz de resolver isso sem ajuda Russ', então eu quero agradecer-lhe novamente por toda a sua ajuda neste.
Outras dicas
Há um monte de desnecessária alongamento do cadeia de escopo em seu código, e uma cadeia de escopo mais tempo vai demorar mais tempo para resolver. Pode ser abreviado para o seguinte
$("navbar a").click(blah)
.hover(foo,bar)
.focus(foo)
.blur(bar);
Esperamos que isso deve resultar em menos de um atraso perceptível. Se você ainda vê lag perceptível após fazer essa alteração, por favor postar o código para as funções de manipulador de eventos como pode haver melhorias que podem ser feitas para que o código também.
EDIT:
Em resposta ao seu comentário, você poderia obter o índice na função usando o passou na propriedade event
target
do objeto, que será o elemento que o evento foi gerado por diante. Assim, para obter o índice de um elemento <a>
em todos os elementos <a>
no <ul>
com id barra de navegação , podemos usar o fato de que cada <a>
está contido dentro de um <li>
, portanto o índice em cada caso será ser o mesmo. Com isto em mente, event.target
será o elemento <a>
que o evento clique é gerado em, event.target.parentNode
será o elemento pai do <a>
que é o <li>
Para obter o índice, você poderia usar
function hoverState(e) {
// get the index of the <a> element, which will be the same
// as the index of the <li> that contains it in the <ul>
//
var index = $(e.target.parentNode).prevAll().length;
//
// get the sign
var sign = (e.type === 'mouseenter' || e.type === 'focus')? 1 : -1;
}
Isto irá remover a necessidade de manipuladores de eventos função anônima envolvendo hoverState.
Aqui está um código reformulado
var statePad=0;
// the purpose of this function is to translate
// the current state of the menu into a different
// graphical representation of the menu state.
//
function stateChanger(ourStatePad) {
var tempVar=ourStatePad;
var tempArray = [0,0,0,0,0];
for (var x=0;x < 5;x++) {
tempArray[x]=tempVar % 10;
tempVar=(tempVar-tempArray[x])/10;
}
// Calculate the proper position in our CSS sprite,
// based on the each link's state, as well as it's neighbors'
//
var arrayIndex=4;
while (arrayIndex--) {
$("#rightpostheader div.block").eq(4 - arrayIndex)
.css(
"backgroundPosition",
//x-position
((4 - arrayIndex) * -100) + "px " +
//y-position
(tempArray[arrayIndex] + ((3 * tempArray[(arrayIndex) + 1]) * -30))) + "px";
}
}
function hoverState(e) {
var index = $(e.target.parentNode).prevAll().length;
var sign = (e.type === 'mouseenter' ||
e.type === 'focus')? 1 : -1;
var placeholder=Math.pow(10,4-index);
if (statePad != placeholder*2)
statePad += (placeholder * sign);
stateChanger(statePad);
}
$("#navbar a")
.click(function(e) {
// might be able to rework this into using hoverState too
var $this = $(e.target);
// get the index of the parent <li>
var index= $this.parent().prevAll().length;
statePad=Math.pow(10,(4-index))*2;
stateChanger(statePad);
$("#navbar a").removeClass('active');
$this.addClass('active');
})
.bind("mouseenter mouseleave focus blur", hoverState);