Javascript non-intrusif, chapitre 2 : comment retrouver les éléments que l’on veut manipuler

Par Christian Heilmann

Cet article est le second d'une série qui en compte 5.

Les développeurs Javascript débutants misent tout sur le HTML.

HTML :
<a href="index.html"
onmouseover="image1.src='1on.gif'"
onmouseout="image1.src='1off.gif'">
<img src="1off.gif" name="image1" border="0" height="150" width="150"
alt="Retour à l'accueil"></a>

Ou, s'ils s'y connaissent un peu mieux :

HTML:
<a href="index.html"
onmouseover="roll('home',1)"
onmouseout="roll('home',0)">
<img src="home.gif" name="home" border="0"
height="150" width="150"
alt="Retour à l'accueil"></a>
Javascript:
// préchargement de l'image
homeoff = new Image();
homeoff.src = 'home.gif';
homeon = new Image();
homeon.src = 'homeoff.gif';
function roll(imgName,a)
{
 imgState=a==0?eval(imgName + 'on.src'):eval(imgName + 'off.src');
 document.images[imgName].src = imgState;
}

Dans les deux cas, tous les gestionnaires d'événements sont dans le HTML, et si le nom de la fonction venait à changer, nous devrions modifier chaque document. De plus, à chaque survol d'image correspond un surplus de code, ce qui ajoute au poids total de la page.

À bas les gestionnaires d'événement imbriqués !

Oublions un instant que la plupart des effets de survol s'obtiennent de nos jours avec des CSS plutôt qu'avec du Javascript. Mettons que nous voulons utiliser le code suivant et créer un effet de survol sur l'image :

HTML:
<a href="index.html"><img src="home.gif" id="home" alt="Retour à l'accueil"></a>

Bon, et comment allons-nous faire bouger tout ça quand la souris passe dessus ?

À la conquête de l'arbre à nœuds

Chaque document XML (y compris XHTML) est un arbre de nœuds. Un nœud est une partie de l'arbre (pensez à un fichier ou un dossier quand vous naviguez dans votre disque dur). Un nœud peut être de douze types différents. Pour le HTML, seuls trois types sont vraiment intéressants : element (un nœud de type 'élément'), TextNode (un nœud de type 'texte') et AttributeNode (un nœud de type 'attribut').

Notre matériel d'escalade

Voyons quelles fonctions et quels attributs nous pouvons utiliser pour parcourir l'arbre d'un document, et comment sauter d'un élément à l'autre.

Fonctions servant à atteindre un élément dans une page

getElementById('elementID')
renvoie l'élément dont l'id est elementID, en tant qu'object (un objet en Javascript).
getElementsByTagName('tag')
renvoie tous les éléments dont la balise est tag, en tant qu'array (un tableau en Javascript).

Bien sûr vous pouvez panacher les deux. Par exemple :

document.getElementById('navigation').getElementsByTagName('a')[3];
renvoie le quatrième lien à l'intérieur de l'élément dont l'id est 'navigation'.
document.getElementsByTagName('div')[2].getElementsByTagName('p')[0];
renvoie le premier paragraphe à l'intérieur de la troisième div du document.

Outils pour se déplacer en partant d'un élément

childNodes
renvoie un tableau de tous les nœuds à l'intérieur du nœud actuel. Il y a aussi firstChild et lastChild, qui sont des raccourcis, respectivement, de childNodes[0] et childNodes[this.childNodes.length-1].
parentNode
l'élément contenant l'élément actuel.
nextSibling
l'élément suivant au même niveau d'arborescence.
previousSibling
l'élément précédent au même niveau d'arborescence.

Ils peuvent être mélangés à l'envi en fonction du besoin.

var other=document.getElementById('nav').childNodes[3].firstChild;
renvoie le premier sous-élément du quatrième enfant de l'élément dont l'id est 'nav'.
var prevlink=o.parentNode.previousSibling.firstChild.childnodes[2];
renvoie le troisième nœud de l'élément précédent qui est au même niveau que l'élément parent de 'o'.

Attributs et fonctions des éléments

attributes
renvoie un tableau de tous les attributs de cet élément. Ne fonctionne pas dans Internet Explorer pour les versions inférieures à la version 6.
data
renvoie ou fixe les données textuelles du nœud.
nodeName
renvoie le nom du nœud (le nom de l'élément HTML).
nodeType
renvoie le type du nœud : 1 si c'est un élément, 2 si c'est un attribut, et 3 si c'est du texte.
nodeValue
renvoie ou fixe la valeur du nœud. Cette valeur est du texte si le nœud est un nœud textuel, l'attribut lui-même si c'est un attribut, ou 'null' (valeur nulle) si c'est un élément.
getAttribute(attribute)
renvoie la valeur de l'attribut attribute.
Javascript:
var monElement=document.getElementById('nav').firstChild;
if(monElement.nodeType==3)
{
 monElement.data='nouveau texte';
}
if(monElement.nodeType==1)
{
 monElement.firstChild.data='nouveau texte';
}

Pour revenir à notre exemple, si nous voulons atteindre l'image, nous pourrons utiliser soit getElementsByTagName, soit getElementById.

HTML:
<a href="index.html"><img src="home.gif" id="home" alt="Retour à l'accueil"></a>
Javascript:
function trouveimg()
{
 var image;
 image=document.getElementById('home');
 if (image)
  {
   image.style.border='3px dashed #ccc';
  }
}

ou :

function trouveimg()
{
 var imgs,i;
 imgs=document.getElementsByTagName('img');
 for(i in imgs)
 {
  if(/home.gif/.test(imgs[i].src))
   {
    imgs[i].style.border='3px dashed #ccc';
   }
  }
}

Il est bien plus simple d'utiliser getElementById, puisque nous n'avons pas à parcourir tous les éléments pour retrouver un identifiant unique. Dans notre exemple, nous avons vérifié que l'attribut src de l'objet image contenait 'home.gif'. Une méthode plus courante consiste à vérifier la présence d'une classe particulière.

HTML:
<a href="index.html"><img src="home.gif" class="roll" alt="Retour à l'accueil"></a>
Javascript:
function trouveimg()
{
 var imgs,i;
 imgs=document.getElementsByTagName('img');
 for(i in imgs)
  {
  if(/roll/.test(imgs[i].className))
   {
    imgs[i].style.border='3px dashed #ccc';
   }
  }
}

Maintenant, pour produire un effet de survol, il nous suffit d'écrire une fonction qui substitue la source de l'image, et ajoute des gestionnaires d'événement à l'image.

function trouveimg()
{
 var imgs,i;
// parcourons toutes les images du document
 imgs=document.getElementsByTagName('img');
 for(i=0;i<imgs.length;i++)
 {
// testons la présence de la classe 'roll'
  if(/roll/.test(imgs[i].className))
  {
// ajoutons la fonction 'roll' à l'image quand la souris passe dessus (onmouseover)
// et quand elle s'en éloigne (onmouseout)
// puis faisons passer l'image elle-même en tant que paramètre de type objet à la fonction roll()
   imgs[i].onmouseover=function(){roll(this);};
   imgs[i].onmouseout=function(){roll(this);};
  }
 }
}

function roll(o)
{
 var src,ftype,newsrc;
// récupérons le src de l'image, et trouvons son extension de fichier
 src = o.src;
 ftype = src.substring(src.lastIndexOf('.'), src.length);
// vérifions si le src comporte déjà la chaîne '_on' et si c'est le cas, supprimons-la
 if(/_on/.test(src))
 {
  newsrc = src.replace('_on','');
 }else{
// sinon, ajoutons '_on' au src
  newsrc = src.replace(ftype, '_on'+ftype);
 }
 o.src=newsrc;
}

window.onload=function(){
 trouveimg();
}

Voir l'exemple en action.

Jusque-là tout va bien, mais nous avons oublié une chose : bien qu'étant un simple enrichissement visuel, un changement d'image au survol devrait aussi bien fonctionner sans souris. Pour ce faire, nous devons vérifier si le lien qui entoure l'image a reçu le focus (NdT : autrement dit, si on a tabulé jusqu'à ce lien), sachant que l'image elle-même n'est pas trouvée au clavier quand elle est dans un lien.

Nous devons donc retrouver l'élément qui contient l'image —dans notre cas, il s'agit du lien. Nous y parviendrons grâce à la commande parentNode. L'objet qui est transmis en tant que paramètre à la fonction roll() va changer ; nous devons donc commencer, là encore, par trouver l'image. Parcourons donc les nœuds enfants ('childNodes') du lien et trouvons lequel est un élément et une image, en vérifiant tour à tour nodeType et nodeName. C'est nécessaire, parce que certains navigateurs voient les espaces blancs du code source comme un nœud à part entière tandis que d'autres les ignorent.

function trouveimg()
{
 var imgs,i;
// Parcourons toutes les images, et trouvons celles qui comportent la classe 'roll'
 imgs=document.getElementsByTagName('img');
 for(i=0;i<imgs.length;i++)
 {
  if(/roll/.test(imgs[i].className))
  {
// ajoutons la fonction 'roll' à l'élément parent de cette image
  imgs[i].parentNode.onmouseover=function(){roll(this);};
  imgs[i].parentNode.onmouseout=function(){roll(this);};
  imgs[i].parentNode.onfocus=function(){roll(this);};
  imgs[i].parentNode.onblur=function(){roll(this);};
  }
 }
}

function roll(o)
{
 var i,isnode,src,ftype,newsrc,nownode;
// parcourons tous les enfants
 for (i=0;i<o.childNodes.length;i++)
 {
  nownode=o.childNodes[i];
// si le nœud est un élément et une image, fixons la variable et sortons de la boucle
  if(nownode.nodeType==1 && /img/i.test(nownode.nodeName))
  {
   isnode=i;
   break;
  }
 }
// vérifions le src et permutons le fichier source de l'image
 src = o.childNodes[isnode].src;
 ftype = src.substring(src.lastIndexOf('.'), src.length);
 if(/_on/.test(src))
 {
  newsrc = src.replace('_on','');
 }else{
  newsrc = src.replace(ftype, '_on'+ftype);
 }
 o.childNodes[isnode].src=newsrc;
}

window.onload=function(){
 trouveimg();
}

Essayez cet exemple qui fonctionne aussi sans souris.

Pourquoi n'essayez-vous pas ?

Il vous suffit de télécharger notre exemple, et de faire les tâches fixées. Suivez les liens vers les solutions pour voir une solution possible. Le code Javascript de ces exemples est directement inséré dans le HTML alors qu'il devrait figurer dans un fichier externe. J'ai cependant ici tout mis dans un seul fichier pour simplifier votre lecture.

  1. Changer la couleur de chaque titre H2 en bleu. Voir la solution.
  2. Encadrer chaque deuxième paragraphe d'une bordure noire. Voir la solution.
  3. Vérifier quel lien est externe (en contrôlant que l'attribut href ne contient pas window.location.hostname) et afficher le href du lien comme texte entre parenthèses juste après le lien. En attendant d'apprendre à le faire proprement, utilisez l'attribut innerHTML de l'objet lien pour changer son contenu. Voir la solution.
  4. Ajouter un gestionnaire onclick à chaque lien qui possède l'attribut target pour ouvrir une nouvelle fenêtre de 400x400 pixels. Voir la solution.

Liens

» À suivre : « Javascript non-intrusif, chapitre 3 : créer du contenu et le détruire ».

Fiche technique

À propos de l'auteur

lang="en">Christian Heilmann
est un contributeur de Digital Web Magazine. La plupart de ses
publications sont écrites dans le métro, en voyageant
à travers Londres, parce qu’il n’y a simplement rien d’autre
à y faire. Un jour il aimerait remettre son propre livre
à ceux qui sont coincés là.

Articles du même auteur

Articles similaires

Voici la liste des dix articles les plus récents en rapport avec cet article :

Intermédiaire

JavaScript

© 2001-2016 Pompage Magazine et les auteurs originaux - Hébergé chez Nursit.com ! - RSS / ATOM - About this site