Domanda

Sto tentando di creare un menu di navigazione che utilizza jQuery. Volevo che gli utenti della tastiera potessero avere la stessa esperienza degli utenti del mouse, quindi sto duplicando la funzionalità presente nel mio gestore di eventi hover() nei miei gestori di eventi focus() e blur(). Per qualche motivo, ciò sta causando un notevole ritardo in Firefox e IE quando l'utente fa clic su un collegamento, che non si verifica quando viene rimosso il codice <=> e <=>. Come posso accelerare questo? Ho ottimizzato quanto le mie conoscenze limitate su javascript consentiranno, ma non ho visto alcun & Quot; speedup & Quot ;, quindi penso che potrebbe essere correlato al modo in cui questi browser gestiscono gli eventi .

C'è qualcosa di grave che sto trascurando? Oppure ci sono modi alternativi per mantenere l'accessibilità per gli utenti della tastiera mentre non si usano questi eventi?

        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);
            }
        );  
    });

Puoi verificarlo qui

È stato utile?

Soluzione 2

L'ho risolto per caso, quasi. Mi sono reso conto che il mio problema non era proprio il ritardo, era solo un sintomo di un & Quot; conflitto di eventi & Quot ;.

Il problema, per quanto ne so, è che focus() viene attivato tramite la tabulazione su un collegamento o un mousedown() su un elemento che può essere attivato. Quindi, ogni volta che si fa clic su un collegamento, viene messo a fuoco. Ma un evento click() non è completo fino al rilascio del mouse. Quindi l'effetto che stavo vedendo in Firefox e IE era il risultato di un leggero ritardo tra mouseup() e .click(). Ho provato a scambiare la <=> gestione degli eventi nel mio codice in <=> e dato che è solo un singolo evento a cui stavo attento, ho deciso di integrarlo nella mia funzione hoverState (). Ho finito con questo:

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);

Tuttavia, ciò ha causato un comportamento bizzarro che ha rovinato la variabile statePad. Sono tornato al codice che Russ Cam mi ha fornito e ho iniziato a ripensare le cose. L'ho provato a Opera, cosa che non avevo ancora fatto, e ha funzionato bene. L'ho provato in Safari e Chrome, e hanno funzionato bene come al solito. L'ho provato su Firefox, cercando solo di capire cosa lo rende diverso e ... stava funzionando!

Ho guardato indietro al mio codice e risulta che stavo ancora vincolando la funzione hoverState all'evento <=>. Non sono esattamente sicuro del perché funzioni, ma funziona. Risolve il problema anche in IE. Strangolare, provoca un nuovo problema in Chrome, è così secondario che non mi preoccuperò nemmeno.

Non credo che sarei stato in grado di risolverlo senza l'aiuto di Russ, quindi voglio ringraziarlo di nuovo per tutto il suo aiuto in questo.

Altri suggerimenti

Ci sono molti inutili la catena dell'ambito nel codice e una catena dell'ambito più lunga richiederà più tempo per essere risolta. Potrebbe essere abbreviato come segue

$("navbar a").click(blah) 
             .hover(foo,bar)
             .focus(foo)
             .blur(bar);

Si spera che questo dovrebbe tradursi in un ritardo notevole. Se dopo aver apportato questa modifica si riscontra ancora un notevole ritardo, si prega di pubblicare il codice per le funzioni del gestore eventi in quanto potrebbero essere apportati miglioramenti anche a quel codice.

Modifica

In risposta al tuo commento, puoi ottenere l'indice nella funzione utilizzando la proprietà event dell'oggetto target passata, che sarà l'elemento su cui è stato generato l'evento. Quindi, per ottenere l'indice di un <a> elemento in tutti gli <ul> elementi nella <li> con ID barra di navigazione , possiamo usare il fatto che ogni event.target è contenuto in un < =>, quindi l'indice in ciascun caso sarà lo stesso. Con questo in mente, event.target.parentNode sarà l'elemento <=> su cui viene generato l'evento click, <=> sarà l'elemento genitore di <=> che è <=>

Per ottenere l'indice, è possibile utilizzare

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;
} 

Ciò eliminerà la necessità di gestori di eventi di funzione anonima che eseguono il wrapping di hoverState.

Ecco del codice rielaborato

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);  
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top