Question

J'essaie de créer un menu de navigation qui utilise du jQuery. Je souhaitais que les utilisateurs de clavier puissent avoir la même expérience que les utilisateurs de souris. Je duplique donc les fonctionnalités de mon gestionnaire d'événements hover() dans mes gestionnaires focus() et blur(). Pour une raison quelconque, cela provoque un décalage notable dans Firefox et IE lorsque l'utilisateur clique sur un lien, ce qui ne se produit pas lorsque le code <=> et <=> est retiré. Comment puis-je accélérer le processus? J'ai optimisé autant que mon javascript le permettait, mais je n'ai vu aucune & «Accélération &» ;, je pense donc que cela pourrait être lié à la façon dont ces navigateurs gèrent les événements .

Y a-t-il quelque chose d'important que je néglige? Ou existe-t-il d'autres moyens de conserver l'accessibilité aux utilisateurs de clavier sans utiliser ces événements?

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

Vous pouvez le vérifier ici

Était-ce utile?

La solution 2

J'ai résolu cela par accident complet, en quelque sorte. J'ai réalisé que mon problème n'était pas vraiment le retard, c'était juste le symptôme d'un & "Conflit d'événements &";

Le problème, autant que je sache, est que focus() est déclenché par une tabulation sur un lien ou par un mousedown() sur un élément pouvant recevoir le focus. Ainsi, chaque fois qu'un lien est cliqué, il devient actif. Cependant, un événement click() n'est pas terminé tant que la souris n'est pas relâchée. Donc, l'effet que je voyais dans Firefox et IE résultait d'un léger retard entre mouseup() et .click(). J'ai essayé d'échanger simplement la <=> gestion des événements dans mon code contre <=>, et comme il ne s'agissait que d'un seul événement que je surveillais, j'ai décidé de l'intégrer à ma fonction hoverState (). J'ai fini avec ceci:

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

Cependant, cela a provoqué un comportement bizarre qui a gâché la variable statePad. Je suis revenu au code fourni par Russ Cam et j'ai commencé à repenser les choses. Je l'ai essayé dans Opera, ce que je n'avais pas encore fait, et ça a bien fonctionné. Je l'ai essayé dans Safari et Chrome, et ils ont bien fonctionné comme d'habitude. Je l'ai essayé dans Firefox, essayant juste de comprendre ce qui le rend différent, et ... ça fonctionnait!

J'ai consulté mon code et il s'avère que je liai toujours la fonction hoverState à l'événement <=>. Je ne sais pas trop pourquoi cela fonctionne, mais ça marche. Cela corrige également le problème dans IE. Étrangle, cela cause un nouveau problème dans Chrome. Il est tellement mineur que je ne vais même pas m'en inquiéter.

Je ne pense pas que j'aurais pu résoudre ce problème sans l'aide de Russ. Je tiens donc à le remercier à nouveau pour toute son aide.

Autres conseils

Il y a beaucoup de allongement de la chaîne de portées dans votre code et une chaîne de portées plus longue sera plus longue à résoudre. Il pourrait être réduit à ce qui suit

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

J'espère que cela devrait permettre de réduire le délai. Si vous constatez toujours un décalage notable après cette modification, signalez le code des fonctions du gestionnaire d'événements, car certaines améliorations pourraient également être apportées à ce code.

EDIT:

En réponse à votre commentaire, vous pouvez obtenir l'index de la fonction en utilisant la propriété event de l'objet passé dans target, qui sera l'élément sur lequel l'événement a été déclenché. Ainsi, pour obtenir l'index d'un élément <a> dans tous les <ul> éléments de la <li> avec l'id barre de navigation , nous pouvons utiliser le fait que chaque event.target est contenu dans un < =>, donc l'index dans chaque cas sera le même. Dans cet esprit, event.target.parentNode sera l'élément <=> sur lequel l'événement click est généré, <=> sera l'élément parent de <=> qui est l'élément <=>

.

Pour obtenir l'index, vous pouvez utiliser

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

Ceci éliminera le besoin de gestionnaires d’événements d’activité anonymes enveloppant hoverState.

Voici un code retravaillé

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);  
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top