OVH Cloud OVH Cloud

Cafouillages events stopPropagation and Co

4 réponses
Avatar
ASM
Sautatous,

Soit un div avec fonctions JS lors des mouseOver et mouseOut.
Soit des liens dans ce div.

Lors du survol des liens :
la fonction du mouseOut du div conteneur se déclenche.
Et *je n'en veux pas*

Démo ici :
http://stephane.moriaux.perso.wanadoo.fr/truc/menu_fadd.htm


Comment y arriver ?

--
Stephane Moriaux et son (moins) vieux Mac déjà dépassé
Contact : http://stephane.moriaux.perso.wanadoo.fr/contact
ASM = Aimable Stéphane Moriaux = Amateur Sasseur Merdouilles

4 réponses

Avatar
Laurent vilday
Soit un div avec fonctions JS lors des mouseOver et mouseOut.
Soit des liens dans ce div.

Lors du survol des liens :
la fonction du mouseOut du div conteneur se déclenche.
Et *je n'en veux pas*

Démo ici :
http://stephane.moriaux.perso.wanadoo.fr/truc/menu_fadd.htm
Comment y arriver ?


Sans ajouter d'events sur les fils (<a>) et sans toucher à la structure
ni HTML ni javascript, voila ce à quoi je suis arrivé :
http://mokhet.com/tests/menu_fadd.html
OK sur mon IE6, Opera9 et FX2

L'astuce c'est d'utiliser les propriétés .target et .relatedTarget (ou
.toElement / .fromElement) de l'event en cours.
http://developer.mozilla.org/en/docs/DOM:event.relatedTarget

function getRelatedTarget(e)
{
var t = e.relatedTarget;
if ( !t )
{
if (e.type == "mouseout")
{
t = e.toElement;
}
else if ( e.type == "mouseover" )
{
t = e.fromElement;
}
}
return t;
}
var related = getRelatedTarget(e);

Avec cette fonction on est désormais capable de savoir quel est
l'élément relié (pas forcémment le déclencheur) à l'event.

Ensuite, dans pop() et nopop(), on va chercher la cible *réelle* de l'event

var cible = e.target || e.srcElement;

Ainsi on a accès à 3 variables :
1) "what" qui est la cible qui est supposée avoir déclenché l'event.
Mais grace au principe du bubbling, ca peut etre un de ses fils qui l'a
déclenché en réalité.
2) "cible" qui est le *réel* déclencheur de l'event
3) "related" qui est le node associé à l'event

Maintenant, avec ces 3 variables définies, voila ce que pop() et nopop()
veulent faire :
1) "what" doit etre égal à "cible" (on ne déclenche rien quand ce n'est
pas "what" qui est le réel initiateur de l'event)
2) "related" ne doit pas etre un des fils, donc pour l'exemple il suffit
de regarder que related.nodeName != 'A'. Ceci dit, selon la structure
réelle, il serait peut etre judicieux d'avoir une function vérifiant que
"what" n'est en aucune manière un parent de "related". M'enfin,
related.nodeName != 'A' est suffisant pour le besoin de l'exemple :)

Ce qui donne ( pareil pour pop() et nopop() ) :

function pop(what,e)
{
e = e || event;
var
cible = e.target || e.srcElement,
related = getRelatedTarget(e);
if ( cible == what && related.nodeName != 'A' )
{
// fade here
}
return false;
}

Sinon, pour l'opacité et IE6, il faut que node.currentStyle.hasLayout
soit true. Hors cette propriété n'ayant pas de setter(), il faut tricher
en lui disant par exemple que la propriété css "zoom" est à "1". Oui, je
sais c'est bizarre :D
http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp

.pop a { zoom:1; filter:alpha(opacity ); }

D'autant que MSDN dit qu'on la propriété hasLayout est définie sur
n'importe quelle valeur de height ou de width, mais évidemment (pour
avoir testé) ça marche pas sur des width:auto

--
laurent

Avatar
ASM
Lors du survol des liens :
la fonction du mouseOut du div conteneur se déclenche.
Et *je n'en veux pas*

http://stephane.moriaux.perso.wanadoo.fr/truc/menu_fadd.htm
Comment y arriver ?


Sans ajouter d'events sur les fils (<a>) et sans toucher à la structure
ni HTML ni javascript, voila ce à quoi je suis arrivé :
http://mokhet.com/tests/menu_fadd.html


Essstraordinaire ! ça fonctionne même avec mon Safari :-)

OK sur mon IE6, Opera9 et FX2

L'astuce c'est d'utiliser les propriétés .target


J'avais vaguement essayé de capter ce target sans vraiment y arriver, et
surtout avant de commencer à m'énerver avec ça je reposais de grands
espoirs sur le stopPropagation (qui apparemment se moque du pb !).

et .relatedTarget (ou
.toElement / .fromElement) de l'event en cours.
http://developer.mozilla.org/en/docs/DOM:event.relatedTarget


Ha! ben ! encore un truc nouveau ce relatedTarget :-/
On ne peut se contenter du e.type ?

function getRelatedTarget(e)
{
var t = e.relatedTarget;
if ( !t )
{
if (e.type == "mouseout")
{
t = e.toElement;
}
else if ( e.type == "mouseover" )
{
t = e.fromElement;
}
}
return t;
}
var related = getRelatedTarget(e);

Avec cette fonction on est désormais capable de savoir quel est
l'élément relié (pas forcémment le déclencheur) à l'event.

Ensuite, dans pop() et nopop(), on va chercher la cible *réelle* de l'event

var cible = e.target || e.srcElement;

Ainsi on a accès à 3 variables :
1) "what" qui est la cible qui est supposée avoir déclenché l'event.
Mais grace au principe du bubbling, ca peut etre un de ses fils qui l'a
déclenché en réalité.


Ouais c'est bien ce qui me mettait la zone
(mouseOver en même temps que mouseOut ... très joli sous Safari)
et pensais que peut-être il était possible d'avoir un stopBubbling et un
stopDescendant ... que les choses soient claires dès le survol du pavé
jaune.

2) "cible" qui est le *réel* déclencheur de l'event
3) "related" qui est le node associé à l'event

Maintenant, avec ces 3 variables définies, voila ce que pop() et nopop()
veulent faire :
1) "what" doit etre égal à "cible" (on ne déclenche rien quand ce n'est
pas "what" qui est le réel initiateur de l'event)
2) "related" ne doit pas etre un des fils, donc pour l'exemple il suffit
de regarder que related.nodeName != 'A'. Ceci dit, selon la structure
réelle, il serait peut etre judicieux d'avoir une function vérifiant que
"what" n'est en aucune manière un parent de "related".


Certes :-)

Ce qui donne ( pareil pour pop() et nopop() ) :

function pop(what,e)
{
e = e || event;
var
cible = e.target || e.srcElement,
related = getRelatedTarget(e);
if ( cible == what && related.nodeName != 'A' )
{
// fade here
}
return false;
}


Heu ... pendant qu'on y est :
ce(s) return false; est(sont) vraiment nécessaire(s) ?

Sinon, pour l'opacité et IE6,


Ha oui! IE ... :-(

il faut que node.currentStyle.hasLayout
soit true. Hors cette propriété n'ayant pas de setter(), il faut tricher
en lui disant par exemple que la propriété css "zoom" est à "1". Oui, je
sais c'est bizarre :D
http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp


.pop a { zoom:1; filter:alpha(opacity ); }


Je ne trouve ni zoom:1; ni node.currentStyle.hasLayout
dans ta page de corrective.

D'autant que MSDN dit qu'on la propriété hasLayout est définie sur
n'importe quelle valeur de height ou de width, mais évidemment (pour
avoir testé) ça marche pas sur des width:auto


On se demande bien à quoi pensent les programmeurs chez M$.
Ça donne touj l'impression que tout est fait à la va vite, et ...
à l'autre équipe de trouver un palliatif au nouveau bug pondu.

En tous cas, merci pour cette nouvelle leçon à propos des events.
Je crois que je n'arriverai jamais à capter ces subtilités :-(

--
Stephane Moriaux et son (moins) vieux Mac déjà dépassé


Avatar
Laurent vilday
http://mokhet.com/tests/menu_fadd.html


Essstraordinaire ! ça fonctionne même avec mon Safari :-)


Tu m'en vois ravi :D

L'astuce c'est d'utiliser les propriétés .target


J'avais vaguement essayé de capter ce target sans vraiment y arriver, et
surtout avant de commencer à m'énerver avec ça je reposais de grands
espoirs sur le stopPropagation (qui apparemment se moque du pb !).


Je pense que c'est les fils qui doivent stopper la propagation, donc
faudrait probablement ajouter un event sur les mouseover/mouseout pour
pas que ça bubble jusqu'au parent. C'est lourd de rajouter des events
sur les fils pour cancel les parents, surtout quand il y a des centaines
voir des milliers (ouch) de fils. Depuis que j'utilise les propriétés
.target et .relatedTarget (et ses amis .toElement et .fromElement) je
trouve que je me prend moins la tête avec ces histoires de bubbling. Ca
permet d'étudier le contexte je trouve.

et .relatedTarget (ou .toElement / .fromElement) de l'event en cours.
http://developer.mozilla.org/en/docs/DOM:event.relatedTarget


Ha! ben ! encore un truc nouveau ce relatedTarget :-/


oops :D

function pop(what,e)
{
e = e || event;
[snip]


return false;
}


Heu ... pendant qu'on y est :
ce(s) return false; est(sont) vraiment nécessaire(s) ?


Non puisque tu fais onmouseover="pop(this, event);return false;"
Mais c'est comme d'habitude, chacun ses petites manies. J'aurais fait
onmouseover="return pop(this, event);" donc dans le handler je retourne
false. Question d'habitude :p

Sinon, pour l'opacité et IE6,


Ha oui! IE ... :-(


lol oui :D

il faut que node.currentStyle.hasLayout soit true. Hors cette
propriété n'ayant pas de setter(), il faut tricher en lui disant par
exemple que la propriété css "zoom" est à "1". Oui, je sais c'est
bizarre :D
http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp
.pop a { zoom:1; filter:alpha(opacity ); }


Je ne trouve ni zoom:1; ni node.currentStyle.hasLayout
dans ta page de corrective.


Ah oui, pardon, un oubli http://www.satzansatz.de/cssd/onhavinglayout.html

--
laurent


Avatar
ASM

Je pense que c'est les fils qui doivent stopper la propagation,


Ha!? j'essaierai voir.

Depuis que j'utilise les propriétés
.target et .relatedTarget (et ses amis .toElement et .fromElement) je
trouve que je me prend moins la tête avec ces histoires de bubbling.


Oui, en tous cas ça a résolu mon pb.

Je ne trouve ni zoom:1; ni node.currentStyle.hasLayout
dans ta page de corrective.


Ah oui, pardon, un oubli http://www.satzansatz.de/cssd/onhavinglayout.html


Alors j'ai mis height: 1%;
puisque zoom n'est pas aimé par le validateur à ce qu'il paraîtrait.
J'espère que ça siéra à IE Win ?



--
Stephane Moriaux et son moins vieux Mac déjà dépassé