Aller au contenu

Menu déroulant JavaScript


ElMoustiko

Sujets conseillés

J'ai terminé une version de menu déroulant via JavaScript.

Le script permet de :

choisir entre des actions au passage de la souris, ou au clique de souris.

Si c'est au clique de souris, il y a encore un choix de façon de faire, ou bien on cache tous les menus pour n'ouvrir que le menu cliqué, ou on laisse les menus déjà ouverts comme ils sont.

Pour choisir entre ces modes de fonctionnement, simplement une zone du script à changer. On copie/colle le morceau choisi présenté plus haut en commentaires.

Le script en lui-même fait une petite vingtaine de lignes (variable suivant la méthode utilisée, on ne compte pas les lignes des ouvertures/fermetures d'accolades), et est totalement extrait du corps du document. Tout le menu est géré grâce au script JavaScript, et mis en forme grâce aux CSS.

Si le JavaScript est desactivé, le menu reste utilisable et est tout simplement ouvert.

Pour ce qui est du code html, 2 versions ont étaient faites, l'une en utilisant les listes de définitions, l'autre en utilisant des titres hN et des listes non ordonnées (version en ligne, je mettrais l'autre version du code html avec le script javascript correspondant si quelqu'un la veux).

Menu testé sous Windows XP, Firefox 0.8, Firefox 1.0PR, Opera 7.23, Internet Explorer 6.0, Mozilla 1.7.1

Si vous avez d'autres configuration logicielles j'écoute vos rapports de bugs eventuels.

Un tutoriel sera réalisé plus tard sur mon site, expliquant les codes html, css et javascript et les différentes possibilités d'utilisation.

Voici donc l'url pour le test : http://www.elmoustikoblog.net/divers/menu/index.html

http://www.elmoustikoblog.net/divers/menu/style.css

http://www.elmoustikoblog.net/divers/menu/script.js

Voilà j'attend vos commentaires, impressions et rapports de bugs !

@++

Lien vers le commentaire
Partager sur d’autres sites

Ca m'a l'air nickel. Bravo :)

Néanmoins :

Serait-il possible de dérouler (ou d'enrouler) le menu par un clic sur le bouton et non par un clique sur le texte ?

Lien vers le commentaire
Partager sur d’autres sites

Pour le click sur le bouton plutot que sur le texte, demande aux developpeurs d'IE ;p

C'est juste que IE ne tient compte que du texte et non de l'element, j'essairai de voir en faisant un petit display: block; ou un width: XXpx ; sur le hN (display: block ; ne devrait rien changé, c'est la propriété par défaut des hN).

Pour ce qui est du curseur: pointer ; sous IE, hmm il me semble que ca fonctionne sous IE6 XP au moins, mais j'ajouterais cursor: hand à la suite pour les mauvais élèves ;p

Si vous avez des configs autres n'hésitez pas à les mentionner pour que je fasse un petit bilan !

Il faudrat que je rajoute un petit "hack JS" aussi je pense pour que le menu ne soit pas pris en compte par les Netscape 4 et IE 4 qui je crois ont carrément du mal ;p

@++

Lien vers le commentaire
Partager sur d’autres sites

Le menu ne fonctionne pas en mode mouseover/mouseout...

Lorsqu'on déplace le curseur pour pointer sur un lien du sous menu ouvert, on quitte le h2 et la fonction enregistrée sur l'évènement 'mouseout' est donc appellée et referme le sous menu.

(firefox 0.9.3)

Lien vers le commentaire
Partager sur d’autres sites

Arrh oui ! Je me serais collé une banane sur la tête j'aurais été moins ridicule ;p

Il faut (a priori, a vue de nez) mettre le onmouseout sur le parentNode, je fait des modifs et des tests pour etre certain !

Merci de m'en faire la remarque, j'avoue être passé très rapidement sur le roll over !

Lien vers le commentaire
Partager sur d’autres sites

Voilà qui est corrigé !

  h2s[i].parentNode.onmouseover = function()
 {
 hideAll();
 var cur_ul = this.getElementsByTagName('ul')[0];
 cur_ul.style.display = "";
 }
 h2s[i].parentNode.onmouseout = function()
 {
 hideAll();
 }

Je suis obligé d'appeler hideAll() ; quand même dans le onmouseover alors qu'apriori il n'y aurait pas besoin, mais quand on quitte la div par en dessous ca bug alors que par le coté ca fonctionne... bizar bizar ! Enfin là ca fonctionne.

Merci d'avoir relevé cette erreur !

_AT_ldo > merci pour les tests, je note ! (t'en penses quoi sinon ? )

Rappel de compatibilité actuel :

*WinXP

Firefox 0.8

Firefox 0.9.3

Firefox 1.0PR

Mozilla 1.7.1

Opera 7.23

Internet Explorer 6.0

*Mac OS X 10.2

Safari

Mozilla

Camino

Internet Explorer 5.2

Lien vers le commentaire
Partager sur d’autres sites

Là, ta fonction enregistrée sur l'évènement 'mouseout' est appellée dés qu'on quitte le h2 et masque le sous menu.

Dans le même temps, on arrive sur le premier élément du sous menu, la fonction enregistrée sur l'évènement 'mouseover' est appellée, faisant réapparaitre le sous menu.

Cela donne une impression de saute d'affichage, d'où l'intérêt de vérifier sur l'évènement 'mouseover' qu'on vient bien d'ailleurs que d'une partie du bloc, et sur l'évènement 'mouseout', que l'on est bien entré dans une partie de la page ne faisant pas partie du bloc.

Lien vers le commentaire
Partager sur d’autres sites

Non la fonction sur le mouseover est gérée par rapport au div parent du h2, h2s.parentNode donc au final :

Quand on passe sur la div englobant titre de menu et sous menu on affiche le sous menu et au sortir de cette même div on cache.

Je ne comprend pas ta remarque là par contre...

Lien vers le commentaire
Partager sur d’autres sites

ahh j'ai *peut etre* compris, en fait quand on vas sur un element enfant de la div parente, on quitte (et on revient en même temps) l'élément parent, c'est ca ?

Si tel est le cas... hmm bah je vois mal une alternative... Et le clignotement, je ne le vois pas, à quoi ça peut etre dû ? à la config je suppose ?

Lien vers le commentaire
Partager sur d’autres sites

arf <_<

Ça veut dire que si je passe d'un lien à un autre dans un sous menu de ton exemple, les évènements mouseover et mouseout seront déclenchés quand même (ce qui est tout à fait normal), bien que l'on n'entre ni ne sorte du sous menu. Donc display mis à none puis aussitôt remis à sa valeur par défaut, donc un affichage saccadé.

Donc il faut vérifier si on entre ou sort vraiment du sous menu pour ne modifier la propriété display que dans ces cas là, et pas quand on se balade entre les enfants du bloc sur lequel sont enregistrés les évènements mouseover et mouseout.

Modifié par Bobe
Lien vers le commentaire
Partager sur d’autres sites

Ahh d'accord... donc il va falloir que je reflechisse à savoir comment verifier que l'on ne sors pas dans la div quand on passe du h2 au ul... hmm comme ca vite fait je vois pas, mais j'y reflechirais (si t'as une piste rapide). En tout cas je reprend pas ca ce soir, je risque de faire plus de n'importe quoi qu'autre chose vu mon état !

Merci des indications et explications ! On va peut etre arriver a un truc formi formidable !

Enfin ca reste bien je trouve quand même, non ? (pour une fois que je suis content de mon boulot ;p)

Lien vers le commentaire
Partager sur d’autres sites

Ahh d'accord... donc il va falloir que je reflechisse à savoir comment verifier que l'on ne sors pas dans la div quand on passe du h2 au ul... hmm comme ca vite fait je vois pas, mais j'y reflechirais (si t'as une piste rapide).

Bah... Retourne dans l'autre topic et regarde le script que j'ai fait, je gère ce problème.

Mais continue ton script, on apprend beaucoup par la pratique :)

Lien vers le commentaire
Partager sur d’autres sites

Wé bon bah j'ai tenté de comprendre, je crois que j'ai saisi le sens de ton script,

j'ai tenté une application à mon cas :

  h2s[i].parentNode.onmouseover = function()
 {
 hideAll();
 var cur_ul = this.getElementsByTagName('ul')[0];
 cur_ul.style.display = "";
 }
 h2s[i].parentNode.onmouseout = function()
 {
 if((this.target != this.childNodes) || (this.event.toElement != this.childNodes))
 {
   hideAll();
 }
 }

Donc bon je me doute que la syntaxe doit etre n'importe quoi, mais je me demandais si j'etais dans l'idée...

En gros je voudrais faire si target de h2s.parentNode (this) n'est pas un childNodes de h2s.parentNode (this) (target ou event.toElement, en gros c'est l'un pour IE et l'autre pour les autres c ca ? event.toElement pour IE ?? )

Bon je vais peut etre te faire vomir Bobe, mais là j'ai fait un test rapide, et j'avoue que je ne sais pas par quel bout m'y prendre...

si tu pouvais m'indiquer au moins si je suis a peu pres sur la bonne voie et si j'ai compris ce qu'il fallait faire.

@++

Lien vers le commentaire
Partager sur d’autres sites

Bon je vais peut etre te faire vomir Bobe, mais là j'ai fait un test rapide, et j'avoue que je ne sais pas par quel bout m'y prendre...

si tu pouvais m'indiquer au moins si je suis a peu pres sur la bonne voie et si j'ai compris ce qu'il fallait faire.

childNodes est une collection (un tableau) tandis que target (qui n'est pas un attribut du this dans ta fonction) est un objet. Tu ne peux pas les comparer ainsi.

L'idée est de remonter l'arbre avec parentNode jusqu'à ce qu'on tombe sur le bloc contenant tout le sous menu (celui sur lequel on enregistre les évènements mouseover et mouseout) ou que l'on arrive à l'objet document (auquel cas, on stoppe la boucle).

Si on a trouvé sur noter chemin le bloc du sous menu, c'est qu'on est dans le sous menu, sinon, si l'on est arrivé jusqu'à l'objet document, c'est qu'on est pas/plus dans le sous menu.

J'ai regardé ton code et je t'invite à consulter la doc officielle pour consolider un peu tes bases du DOM:

http://www.yoyodesign.org/doc/w3c/w3c.html#dom2 (traduction française)

Pour le modèle d'évènement, voir aussi:

http://www.brainjar.com/dhtml/events/default.asp

http://www.quirksmode.org/js/contents.html#events

Lien vers le commentaire
Partager sur d’autres sites

Je vais consulter les liens que tu m'as donné, mais j'ai repensé un peu moins bettement mon idée premiere, en effet, childNodes est un array, je pensais donc faire un truc du style :

  h2s[i].parentNode.onmouseover = function()
{
 hideAll();
 var cur_ul = this.getElementsByTagName('ul')[0];
 cur_ul.style.display = "";
}
h2s[i].parentNode.onmouseout = function()
{
  var childs = this.childNodes;
 for(var k = 0; k < childs.length; k++)
 {
   if((this.target.nodeName != childs[k].nodeName) || (this.event.toElement != childs[k].nodeName))
   {
    hideAll();
   }
 }
}

Donc on recupere les elements enfant dans childs (array) et on test le nodeName du target par rapport au nodeName de childs[k], ca parait faisable (dans ma tete), je n'ai pas testé (en semaine, j'ai pas trop le temps... je ne pourrais m'attaquer à tes liens que ce week end). Mais tu disais que target n'etait pas un attribut de this.. pourquoi ? (this correspond à h2s.parentNode)

Sinon les evenements mouseover et mouseout sont fait sur le parentNode du h2

j'ai

<div>
  <h2>titre</h2>
  <ul>
     <li>...</li>
     ...
     <li>...</li>
  </ul>
</div>

donc le parentNode de h2 est div, et je veux tester que le mouseOut ne conduit pas sur div.childNodes c'est à dire, h2 ou ul. Enfin je crois que tu avais compris.

Peut confirmer ou infirmer que ce que j'ai fait avec la boucle for est bon ?

Et m'expliquer ce que tu voulais dire : "target (qui n'est pas un attribut du this dans ta fonction"

Et aussi (si tu a le temps ;) )

target c'est pour IE ou les autres ? (et vice versa avec event.toElement). Sinon je regarderais ce week end.

Voila, merci de t'interesser à mon probleme quand meme !!! j'espere réussir à faire un truc pas mal au final !

@++

Modifié par ElMoustiko
Lien vers le commentaire
Partager sur d’autres sites

Bon, je n'ai pas eu l'occasion de toucher au script, mais j'ai parcouru les sites que tu m'as indiqué, et je crois que ça devrait le faire, ce sont vraiment de bonnes sources je trouve ! Pourquoi on ne les trouves ps sur google ? Je ne dois pas chercher les bonnes choses ;) En tout cas merci bien de me les avoir indiqué, je pense que je vais pouvoir réussir à faire quelque chose de tout ceci, mais quand, telle est la question !

Tu auras peut etre des nouvelles milieu de semaine ^^ Et j'espere que tu pourras me dire ce qui va et ce qui ne va pas

@++

Lien vers le commentaire
Partager sur d’autres sites

Bon j'ai utilisé ce que tu m'avais donné Bobe, et le controle sur le mouseout fonctionne (un peu bidouille pour les tests) mais j'ai toujours le clignotement...

	for(var i = 0; i < h2s.length; i++)
{
 h2s[i].parentNode.onmouseover = function()
 {
 hideAll();
 var cur_ul = this.getElementsByTagName('ul')[0];
 cur_ul.style.display = "";
 }

 h2s[i].parentNode.onmouseout = function(event)
 {
var relTarg;
if (!event) var event = window.event;
if (event.relatedTarget) relTarg = event.relatedTarget;
else if (event.toElement) relTarg = event.toElement;
if ((relTarg.nodeName.toLowerCase() != 'ul') && (relTarg.nodeName.toLowerCase() != 'li') && (relTarg.nodeName.toLowerCase() != 'h2') && (relTarg.nodeName.toLowerCase() != 'a'))
{
 alert(relTarg.nodeName.toLowerCase());
 hideAll();
 }
 //alert(relTarg.nodeName);
 }
}
}

Donc je récupere l'element d'arrivé (relTarg) et si != li, ul, h2, a (bidouille, si j'arrive à regler le probleme, je ferais autrement) on fait un alert de l'element relTarg, et on cache le reste sinon, rien.

Donc ca fonctionne, si = li, ul, h2, a, ... le menu ne se ferme pas, sinon le menu se ferme et j'ai le alert qui me met body, html, div suivant comment je balade ma souris. Mais, j'ai toujours le clignotement... alors que la fonction est inhibé en principe. Ou est-ce dû au mouseover ? ou a autre chose...

Pour ce qui est de ma bidouille sur un des liens que tu me donnais, il y avait une boucle while qui s'arretait qd il n'y avait plus d'element parent à l'element testé (ou un truc du genre), je compte donc la reprendre, mais je prefere faire etape par etape pour bien cerner les choses, et là j'arrive à un truc que je ne comprend pas, alors si tu avais une explication...

Lien vers le commentaire
Partager sur d’autres sites

Bon en fait après un simple test, que j'aurais dû faire avant :blush: c'etait bien a cause du mouseover que j'avais un cligno, c'etait l'appelle à la fonction hideAll(); du mouseover, un petit oubli :blush:

Donc impecable, je n'aurais plus que modifier la bidouille.

Je met le résultat actuel pour ceux qui veulent :

http://www.elmoustikoblog.net/tutoriels/js/menu2-bis/

Il reste un problème, sous IE, le menu se ferme tout seul au sortir du titre, si je rajoute 'div' dans mes tests de mouseout, ca fonctionne, mais là il faut attendre de quitter la div conteneuse totale pour arriver à fermer les sous menus...

Donc il faudrait trouver d'ou vient ce probème...

Si quelqu'un à une idée !

[edit]

Donc je reformule un peu le problème :

Il faut changer le if pour obtenir comme conditions :

if(relTarg != this.childNodes && relTarg != this)

En gros et syntaxiquement incorect, donc il faut pour fermer le menu que l'element d'arrivé soit différent d'un élément enfant de h2.parentNode et différent de h2.parentNode.childNodes (en utilisant une boucle for).

Si quelqu'un a une piste, ou si je me gourre de méthode, je suis preneur.

Modifié par ElMoustiko
Lien vers le commentaire
Partager sur d’autres sites

Euh, je vais m'inscrire en faux(cille) dans ce débat....

Bon bref, ce que je voulais dire, c'est que sous IE6, chez moi, lorsque le curseur pointe sur "titre", le menu déroule bien, malheureusement, impossible de pointer sur un item (le menu se referme)...

xpatval.

Lien vers le commentaire
Partager sur d’autres sites

Puisqu'ElMoustiko essaye de me convaincre que le javascript n'est pas le mal incarné, j'ai testé :P

Précision sérieuse tout de suite : je ne crois pas que ce soit le mal incarné et les scripts d'ElMoustiko sont passionnants à suivre.

Revenons à nos moutons :

Sous Opera

- au chargement de la page, c'est un peu surprenant : le menu apparaît intégralement, et puis "plop", tout disparaît ! En fait, javascript a commis son crime après le rendu HTML brut et après le rendu CSS de la page, le menu s'est donc "replié", d'où cet effet suprenant.

-Les items se déroulent tout à fait normalement. Je passe mon curseur sur l'item 1, il s'ouvre... Je descends les sous-items... Je vais passer de "item 1.9" au "titre 1" qui suit... et Argh ! Tout s'est refermé !

C'est logique puisque je ne suis plus en "on mouse over" sur l'élément enfant, mais que je suis revenu sur un "on mouse over" de quoi au juste ? peut-être bien le body ? Bref, je m'aperçois que les déplacements intuitifs de ma souris n'induisent pas les comportements attendus du menu.

J'arrête là le test: en bon utilisateur que ça agace, je ne lit pas le site.

Sous IE

- Premier test avec IE5.0 Windows... C'est pas charitable, je sais. Mais n'empêche que si veux cliquer sur un sous-item du menu... Je peux toujours courir ! Dès que mon curseur de souris quitte "Titre ", tout se replie !

Je me suis encore arrêté là, puisque je suis vraiment le cas type du client-roi, c'est à dire un râleur impénitent.

Sans souris

Je n'ai pas essayé. On verra demain :D

Conclusion sérieuse

Le menu déroulant pose de tels problèmes:

- d'interopérabilité, avec ou sans notion très large de la dégradation admissible,

- d'accessibilité (essayez sans souris, je l'ai fait en fait)

... que c'est définitivement une idée aussi abominable que séduisante.

Cela n'enlève rien au mérite de cette tentative, ni de l'entreprise javascript d'ElMoustiko ici, dont le script d'images vignettes/agrandies sur la même page est excellent.

Ici, ce n'est pas le script qui est mauvais, c'est l'idée de menu déroulant Web dans le cadre des technologies actuelles ;)

Lien vers le commentaire
Partager sur d’autres sites

Veuillez vous connecter pour commenter

Vous pourrez laisser un commentaire après vous êtes connecté.



Connectez-vous maintenant
×
×
  • Créer...