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

Foi útil?

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);  
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top