Pour votre progression, c'est très important de finir le TP précédent avant de commencer celui-ci.
Commençons ce TP par une rapide révision des notions du TP précédent.
HTML:
<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>
JS:
XYZ.css('color','red');
Que faut-il écrire à la place de XYZ pour afficher tous les textes "bla bla bla" en rouge ?
Décomposons la ligne suivante en plusieurs parties:
$('p').css('color','red');
HTML:
<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>
CSS:
.important
{
color: red;
}
JS:
$('p').XYZ;On a vu, au premier cours, qu'on pouvait, avec une fonction jQuery, ajouter une classe à un élément.
HTML:
<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>
CSS:
.important
{
color: red;
}
Combien d'éléments HTML ont class="important" après l'exécution du JS suivant :
$('p').addClass('important');
HTML:
<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>
JS:
var el=XXX;
$('body').YYY(el);
On veut ajouter un 4e paragraphe.
Que faut-il écrire à la place de XXX ?
(en cas de difficulté: cours)
HTML:
<body>
<h1>Ceci est un titre</h1>
<p>bla bla bla</p>
<p>bla bla bla</p>
<p>bla bla bla</p>
</body>
JS:
var el=$('<p></p>');
$('body').YYY(el);
On veut ajouter un 4e paragraphe.
Que faut-il écrire à la place de YYY ?Au premier TP on a écrit des petits programmes en JavaScript simples.
Pour aller plus loin, on a besoin de voir les notions de base de la syntaxe et de l'utilisation du JavaScript.
Pour déclarer une variable on utilise généralement "var".
Ouvrez la console des outils de dév.
Tapez : "var x=123;" (suivi d'entrée)
Puis tapez juste "x" (suivi d'entrée)
Vous avez crée une variable appelée "x".
Elle contient une valeur (123) de type "number".
Maintenant, tapez x="bonjour";
"x" contient maintenant une chaîne de caractères (string).
Le changement entre nombre et string s'est fait automatiquement. C'est ce qu'on appelle le "typage dynamique".
(ça ressemble beaucoup au PHP)
var a =1;
exemple_1();
console.log(a);
console.log(a);
function exemple_1()
{
a=2;
}
"a" est définie en dehors de toute fonction. Elle est donc globale (comme en PHP).
On peut donc l'utiliser directement dans la fonction exemple_1 (En PHP, il faudrait utiliser "global").
La variable "a" dans exemple_1() est la même que la variable "a" à l'extérieur.
var a =1;
exemple_1();
console.log(a);
console.log(a);
function exemple_1()
{
a=2;
}
Qu'affiche ce programme ?
On peut définir une variable dans une fonction.
Elle a une portée (scope) locale.
Dans cet exemple il y a deux variables "a" différentes :
var a =1;
exemple_1();
console.log(a);
console.log(a);
exemple_2();
console.log(a);
function exemple_1()
{
a=2;
}
function exemple_2()
{
var a=3;
}
var a =1;
exemple_1();
console.log(a);
console.log(a);
exemple_2();
console.log(a);
function exemple_1()
{
a=2;
}
function exemple_2()
{
var a=3;
}
En JavaScript les fonctions peuvent être définies à l'intérieur d'autres fonctions.
C'est très utilisé.
La portée est la même que pour variables locales:
function exemple_1()
{
// ici on peut appeler exemple_2();
exemple_2();
// Par contre, exemple_3() n'est pas accessible d'ici.
function exemple_2()
{
// ici on peut appeler exemple_3();
exemple_3();
function exemple_3()
{
}
}
}
En JavaScript les fonctions sont des objets. Elles peuvent être mises dans des variables et manipulées comme n'importe quel objet dans une variable.
C'est une différence importante avec d'autres langages (Java, C...).
// Exemple avec une fonction déclarée séparément
var a=exemple_1;
a();
function exemple_1()
{
console.log('Bonjour');
}
// Exemple avec une fonction anonyme
var b=function()
{
console.log("Au-revoir");
};
b();
Une fonction étant un objet, on peut la passer en argument à une autre fonction.
C'est ce qu'on a fait souvent au TP-1 avec jQuery:
$('img').mousemove(function(event)On crée une fonction anonyme (function(event){...}) et on la passe directement en argument à la fonction .mousemove()
{
$('#affiche-x').text(event.pageX);
$('#affiche-y').text(event.pageY);
});
function abc()
{
return 123;
}
var z=function()
{
return 456;
}
Dans chacun de ces exemples, que contient la variable "a" ?
function abc()
{
return true;
}
Dans les exemples suivants, quel argument reçoit la fonction "click" ?
Quelles saisies fonctionnent pour
/^a/
Quelles saisies fonctionnent pour
/a$/
Quelles expressions fonctionnent ?
Les crochets représentent un seul caractère parmi plusieurs.
Le tiret peut-être utilisé pour représenter une gamme de caractères.
Par exemple :
[ab] veut dire "soit a, soit b"
[abcd] veut dire "soit a, soit b, soit c, soit d".
[a-d] veut dire la même chose que [abcd] "soit a, soit b, soit c, soit d".
[0-9] veut dire la même chose que [0123456789], c'est à dire "un chiffre"
[a-z] veut dire "une lettre minuscule"
Quelles saisies fonctionnent pour
/^a[bcd]e$/
Le "+" et le "*" permettent d'indiquer une répétition de l'expression qui précède.
Par exemple:
a+ veut dire "une ou plus lettres a", exemples: "a", "aaaaa", "aaaaaa"
abc+ veut dire "a, suivi de b, suivi de une ou plus fois c". exemples: "abc", "abcc", "abcccccccc"
a* veut dire "zéro ou plus lettres a", exemples: "" (vide), "a", "aaaaaa"
abc* veut dire "a, suivi de b, suivi de zéro ou plus fois c". exemples: "ab", "abc", "abcccccccc"
[ab]+ comme si on répétait l'expression [ab] un nombre de fois [ab][ab][ab]... : exemple "baababbbabbabba"
Quelles saisies fonctionnent pour
/^ab+c$/
Quelles saisies fonctionnent pour
/^x[rst]y$/
Quelles saisies fonctionnent pour
/^xy+z$/
Quelles saisies fonctionnent pour
/^x[ab]+y$/
Quelles saisies fonctionnent pour
/^xy*z$/
Le "." représente n'importe quel caractère (un seul)
Quelles saisies fonctionnent pour
/^x.y$/
Quelles saisies fonctionnent pour
/^x[a-e]z$/
Par exemple "1234" fonctionnerait, ce qui est ok, mais "abc1234xyz" fonctionnerait aussi, ce qui n'est pas souhaité.
/^[a-z]+@[a-z]+\.[a-z]+$/.test('aqsdfsdf')
Voila!Nous avons une expression rationnelle qui nous permet de vérifier des adresses mails simples.
Une expression plus complète
La validation d'une adresse mail correspondant aux normes RFC 822, RFC 5322 est très très compliquée, mais en pratique, on peut simplifier.
Un site de référence en la matière conseille :
/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test("aaa@bbb.ccc")
/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test("aaabbb.ccc")
[^abcd]
Qui veut dire « tout caractère SAUF a, b, c ou d. »
Attention à ne pas confondre avec le "^" en dehors de crochets, qui veut dire « le début de la chaîne ».
Un autre exemple:
[^a-z]
Qui veut dire « Tout caractère sauf une lettre. »
Un autre exemple :
si on veut trouver quelque-chose qui ressemble à une balise : <div class="xyz">
On peut écrire :
<[^>]+>
Çà se lit "<" suivi d'un n'importe quel caractère qui ne soit pas ">", ceci au moins une fois, suivi de ">".
On veut identifier une expression des chaînes du type
nom="Toto"
prenom="Jo"
adresse="123 rue grande, Trifouilli"
C'est à dire : une suite de lettres minuscules, suivie d'un égal suivi d'un guillemet, suivi de caractères qui ne sont pas des guillemets, suivi d'un guillemet.
Écrivez l'expression entière : /^...$/
Reprenons l'exercice de la fin du TP-1, on va le renommer exo-1:
exo-1.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST">
<p><label>Nom : <input id="nom" name="nom" type="text"/></label><span id="erreur-nom">Non valide !</span></p>
<p><label>Login : <input id="login" name="login" type="text"/></label></p>
</form>
</body>
</html>
CSS:
#erreur-nom
{
color: red;
margin-left: 1em;
display: none;
}
JS:
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");
$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée");
var texte=$("#nom").val();
if(/[^a-zA-Z '-]/.test(texte))
{
$('#erreur-nom').show();
}
else
{
$('#erreur-nom').hide();
}
texte=texte.toLowerCase();
$('#login').val(texte);
});
console.log("La mise en place est finie. En attente d'événements...");
});
Vérifiez que tout marche bien.
On a besoin de manipuler des chaînes de caractères (String).
Les fonctionnalités les plus utiles :
Retrouvez la documentation ici.
Dans la console tapez :
var a="bonjour"
Ensuite tapez:
a.length
Ensuite tapez :
a=a+" c'est moi"
a.replace(/o/,"X")
Attention, le résultat du remplacement est affiché, mais "a" n'a pas été modifié (pour ca : a=a.replace(/o/,"X") )
/xyz/ est une expression rationnellea.replace(/o/g,"X")"bonjour c'est moi" => "bXnjXur c'est mXi"
/b.*jour/.test("bonjour")
Rappel: /b.*jour/ se lit :
"b" suivi de n'importe quelle lettre (.) répétée zéro ou plus fois (*) suivi de "j", suivi de "o" suivi de "u", suivi de "r"
Essayez ensuite :
/b.*jour/.test("aurevoir")
On veut que le "Login" proposé soit une version simplifié du "Nom".
Faites en sorte que lorsque l'utilisateur tape dans le champs Nom, tous les caractères (sauf les lettres) soient remplacés par un tiret "-".
Exemple (l'espace a été remplacé par un tiret)
...
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
...
En vous inspirant de la ligne Nom, complétez le HTML du formulaire pour obtenir l'affichage de la figure.
(Faites uniquement le HTML, on verra le JS après).
exo-1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST">
<p>
<label>
Nom :
<input id="nom" name="nom" type="text"/>
</label>
<span id="erreur-nom" class="erreur">Non valide !</span>
</p>
<p>
<label>
Login :
<input id="login" name="login" type="text"/>
</label>
</p>
<p>
<label>
Mot de passe :
<input id="mdp" name="mdp" type="password"/>
</label>
<span id="erreur-mdp" class="erreur">Trop court !</span>
</p>
<p>
<label>
Confirmation :
<input id="confirm" name="confirm" type="password"/>
</label>
<span id="erreur-confirm" class="erreur">Différents !</span>
</p>
<p>
<input id="bouton" type="submit" value="Envoyer" />
</p>
</form>
</body>
</html>
if ( AAA ) { BBB.show(); } else { BBB.hide(); }Peut s'écrire plus simplement :
BBB.toggle(AAA);
exo-1.js :
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");
$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée dans nom");
var texte=$("#nom").val();
$('#erreur-nom').toggle(/[^a-zA-Z '-]/.test(texte));
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
});
$('#mdp').keyup(function(event)
{
console.log("Une touche a été appuyée dans mdp");
var mdp=$('#mdp').val();
$('#erreur-mdp').toggle(mdp.length<6);
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('#confirm').keyup(function(event)
{
console.log("Une touche a été appuyée dans confirm");
var mdp=$('#mdp').val();
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
console.log("La mise en place est finie. En attente d'événements...");
});
On veut ajouter un champs "Email" au formulaire et afficher un message d'erreur si l'adresse mail saisie ne correspond pas à une expression rationnelle.
Complétez le HTML et le JS pour obtenir le résultat décrit par la figure.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST">
<p>
<label>
Nom :
<input id="nom" name="nom" type="text"/>
</label>
<span id="erreur-nom" class="erreur">Non valide !</span>
</p>
<p>
<label>
Login :
<input id="login" name="login" type="text"/>
</label>
</p>
<p>
<label>
Email :
<input id="email" name="email" type="text"/>
</label>
<span id="erreur-email" class="erreur">Non valide !</span>
</p>
<p>
<label>
Mot de passe :
<input id="mdp" name="mdp" type="password"/>
</label>
<span id="erreur-mdp" class="erreur">Trop court !</span>
</p>
<p>
<label>
Confirmation :
<input id="confirm" name="confirm" type="password"/>
</label>
<span id="erreur-confirm" class="erreur">Différents !</span>
</p>
<p>
<input id="bouton" type="submit" value="Envoyer" />
</p>
</form>
</body>
</html>
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");
$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée dans nom");
var texte=$("#nom").val();
$('#erreur-nom').toggle(/[^a-zA-Z '-]/.test(texte));
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
});
$('#email').keyup(function(event)
{
console.log("Une touche a été appuyée dans email");
var email=$('#email').val();
var emailEstOk=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i.test(email);
$('#erreur-email').toggle(emailEstOk===false);
});
$('#mdp').keyup(function(event)
{
console.log("Une touche a été appuyée dans mdp");
var mdp=$('#mdp').val();
$('#erreur-mdp').toggle(mdp.length<6);
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('#confirm').keyup(function(event)
{
console.log("Une touche a été appuyée dans confirm");
var mdp=$('#mdp').val();
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
console.log("La mise en place est finie. En attente d'événements...");
});
Les actions de l'utilisateur sont gérées par des événements.
L'action par défaut de certains de ces événements peut être annulée avec la fonction event.preventDefault()
Voyons un exemple:
<a href="http://exemple.org">un lien</a>
$('a').click(function(event)
{
event.preventDefault();
});
L'action par défaut quand on clique sur un lien c'est de "suivre ce lien" (changer de page...).
En appelant .preventDefault(), cette action est annulée: rien ne se passe quand on clique sur le lien.
Pour l'instant notre formulaire ne fait rien lorsqu'on appuie sur le bouton "Envoyer".
Ajoutez une "action" au formulaire.
<form method="POST"> => <form method="POST" action="traitement.html">
Créez un fichier traitement.html avec à l'intérieur, juste une phrase. Par exemple "Formulaire en cours de traitement".
(En pratique, on créerait, par exemple, un fichier php pour traiter réellement le formulaire)
Rafraîchissez la page et vérifiez que lorsque vous appuyez sur "Envoyer", vous êtes bien envoyé sur traitement.html
On veut bloquer l'envoi du formulaire s'il y a une erreur affichée.
Il nous faut donc:
AAA+BBB) réagir à l'événement "submit" du formulaire
Attention: l'utilisateur pourrait soumettre le formulaire sans appuyer sur le bouton. Par exemple, il pourrait appuyer sur la touche "entrée" dans un champs texte. C'est pourquoi il existe un événement spécial appelé "submit" et qui est envoyé au <form>. Il est donc préférable d'utiliser celui-ci que d'utiliser l'événement "click" sur le bouton <input>.
CCC) vérifier si un message d'erreur est affiché
DDD) si c'est le cas bloquer / annuler l'événement
EEE) afficher un avertissement
$('AAA').BBB(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});
On va voir ensemble, dans les pages suivantes, ces points.
Important : vérifiez que les messages d'erreur de votre formulaire ont bien class="erreur",
exemple: <span id="erreur-nom" class="erreur">
AAA+BBB) réagir à l'événement "submit" du formulaire
CCC) vérifier si un message d'erreur est affiché
DDD) si c'est le cas bloquer / annuler l'événement
EEE) afficher un avertissement
$('AAA').BBB(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});
On veut réagir à l'événement "submit" généré par le formulaire (pas par le bouton).
Que faut-il écrire à la place de AAA ?
En effet, il se pourrait qu'un utilisateur soumette le formulaire en appuyant sur la touche entrée dans un champs texte ... donc sans cliquer sulr bouton.
AAA+BBB) réagir à l'événement "submit" du formulaire
CCC) vérifier si un message d'erreur est affiché
DDD) si c'est le cas bloquer / annuler l'événement
EEE) afficher un avertissement
$('form').submit(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});
Vous anticipez la question suivante. Ici, on ne s'occupe pas encore de compter les erreurs.
DDD) si c'est le cas bloquer / annuler l'événement
EEE) afficher un avertissement
$('form').submit(function(event)
{
if(CCC)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});
DDD) si c'est le cas bloquer / annuler l'événement
EEE) afficher un avertissement
$('form').submit(function(event)
{
if($('.erreur:visible').length!==0)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});
preventDefault est une fonction...
EEE) afficher un avertissement
$('form').submit(function(event)
{
if($('.erreur:visible').length!==0)
{
DDD;
EEE('Merci de corriger les erreurs.');
}
});
Vérifiez que tout marche bien.
N'oubliez pas de recharger la page du formulaire après avoir fait des modifications.
exo-1.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>exo-1</title>
<link type="text/css" rel="stylesheet" href="exo-1.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="exo-1.js"></script>
</head>
<body>
<h1>Vos identifiants:</h1>
<form method="POST" action="traitement.html">
<p>
<label>
Nom :
<input id="nom" name="nom" type="text"/>
</label>
<span id="erreur-nom" class="erreur">Non valide !</span>
</p>
<p>
<label>
Login :
<input id="login" name="login" type="text"/>
</label>
</p>
<p>
<label>
Email :
<input id="email" name="email" type="text"/>
</label>
<span id="erreur-email" class="erreur">Non valide !</span>
</p>
<p>
<label>
Mot de passe :
<input id="mdp" name="mdp" type="password"/>
</label>
<span id="erreur-mdp" class="erreur">Trop court !</span>
</p>
<p>
<label>
Confirmation :
<input id="confirm" name="confirm" type="password"/>
</label>
<span id="erreur-confirm" class="erreur">Différents !</span>
</p>
<p>
<input id="bouton" type="submit" value="Envoyer" />
</p>
</form>
</body>
</html>
traitement.html :
Formulaire en cours de traitement.
exo-1.css :
.erreur
{
color: red;
margin-left: 1em;
display: none;
}
exo-1.js :
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est prêt");
$('#nom').keyup(function(event)
{
console.log("Une touche a été appuyée dans nom");
var texte=$("#nom").val();
$('#erreur-nom').toggle(/[^a-zA-Z '-]/.test(texte));
texte=texte.toLowerCase();
texte=texte.replace(/[^a-z]/g,'-');
$('#login').val(texte);
});
$('#email').keyup(function(event)
{
console.log("Une touche a été appuyée dans email");
var email=$('#email').val();
$('#erreur-email').toggle(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i.test(email)===false);
});
$('#mdp').keyup(function(event)
{
console.log("Une touche a été appuyée dans mdp");
var mdp=$('#mdp').val();
$('#erreur-mdp').toggle(mdp.length<6);
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('#confirm').keyup(function(event)
{
console.log("Une touche a été appuyée dans confirm");
var mdp=$('#mdp').val();
var confirm=$('#confirm').val();
$('#erreur-confirm').toggle(mdp!==confirm);
});
$('form').submit(function(event)
{
if($('.erreur:visible').length!==0)
{
event.preventDefault();
alert('Merci de corriger les erreurs.');
}
});
console.log("La mise en place est finie. En attente d'événements...");
});
On va prendre un moment pour revoir les sélecteurs CSS.
Ils seront très utiles non seulement pour la mise en page, mais aussi en JS (notamment dans jQuery).
Un sélecteur CSS sert à dire « je veux appliquer ce style à tels éléments ».
Pour l'instant on a vu
Comment faire pour, par exemple, « appliquer ce style à tous les éléments <a> contenus dans un titre <h1> » ?
Prenons un autre exemple:
<ul id="liste1">
<li>abc</li>
<li>def</li>
</ul>
<ul id="liste2">
<li>xyz</li>
<li>rst</li>
</ul>
Supposons qu'on veuille changer uniquement la couleur des "li" de la deuxième liste.
li {color: red;}
ne marche pas, car elle change la couleur des "li" dans les deux listes.
On peut utiliser un sélecteur composé de deux sélecteurs simples:
#liste2 li {color: red;}
L'espace entre "#liste2" et "li" est très important: il veut dire "descendant de".
Donc: "#liste2 li" veut dire "tous les li qui sont descendants de #liste2
Quel(s) élément(s) correspondent au sélecteur suivant?
li a
Quel(s) élément(s) correspondent au sélecteur suivant?
ul a
Quel(s) élément(s) correspondent au sélecteur suivant?
img p
Quel(s) élément(s) correspondent au sélecteur suivant?
.auth p img
Quel(s) élément(s) correspondent au sélecteur suivant?
#menu .actif
Quel(s) élément(s) correspondent au sélecteur suivant?
p>img
Quel(s) élément(s) correspondent au sélecteur suivant?
body>a
On peut aussi composer des sélecteurs en les accolant. Regardons ça sur un exemple:
<h1 class="actu">Mon titre</h1>
<p class="actu">
<strong class="actu">abc</strong> defg <a href="...">un lien </a>
</p>
Par exemple, imaginons qu'il y ait de nombreux types d'éléments (des "p" des "h1" ...) ayant tous une même classe "actu". On pourrait alors sélectionner uniquement les paragraphes ayant la classe "actu" comme ceci:
p.actu { color: red;}
(remarquez: il n'y a pas d'espace entre "p" et ".actu")
"p.actu" veut dire : les éléments à la fois de type "p" et appartenant à la classe "actu"
et ensuite on pourrait continuer, par exemple en spécifiant une relation de descendance:
p.actu a { color: red;}
qui veut dire : les éléments "a" contenus dans des paragraphes de classe "actu" seront en rouge
Ce genre d'approche est très utilisée en pratique.
On peut faire la même chose avec les id:
ul#menu { color: red;}
Comme il n'y a qu'un seul élément avec id="menu", ceci peut paraître redondant. Mais il y a des situations où c'est utile.
Quel(s) élément(s) correspondent au sélecteur suivant?
p.auth
Quel(s) élément(s) correspondent au sélecteur suivant?
ul#menu
Quel(s) élément(s) correspondent au sélecteur suivant?
.auth a.externe img
Quel(s) élément(s) correspondent au sélecteur suivant?
body.auth h2
Dans les exercices suivants nous allons voir comment des règles des style peuvent s'appliquer indirectement à des éléments et ce qu'il se passe lorsque plusieurs règles différentes s'appliquent à un même élément.
La priorité se calcule comme suit:
Supposons que les sélecteurs suivants s'appliquent tous sur un élément.
Classez les par ordre de priorité (1= le plus prioritaire)
HTML:
<p id="intro">
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>
CSS:
#lienpage { color: red;}
a { color: green;}
.externe { color: blue;}
Quelle est la couleur du mot « page » ?
HTML:
<p id="intro">
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>
CSS:
a.externe { color: red;}
a { color: green;}
#intro a { color: blue;}
Quelle est la couleur du mot « page » ?
HTML:
<p id="intro">
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>
CSS:
#lienpage { color: red;}
#intro .externe { color: green;}
#intro a { color: blue;}
Quelle est la couleur du mot « page » ?
HTML:
<p id="intro">
Une jolie <a href="page.html" class="externe" id="lienpage">page</a>.
</p>
CSS:
#intro a { color: red;}
a.externe { color: green;}
#intro a .externe { color: blue;}
Quelle est la couleur du mot « page » ?
(attention piège, lisez attentivement)
Dans les pages suivantes on va réaliser, ensemble, les onglets de la figure de droite.
Si vous êtes en retard, il est préférable d'aller directement à la correction de la partie CSS, cette partie n'etant pas indispensable à l'apprentissage du JavaScript.
Commençons par le CSS.
Dans cette partie, le HTML est fixé. Vous ne devez pas le changer. Vous pouvez uniquement modifier le CSS.
Créez le fichier suivant:
onglets.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>onglets</title>
<link type="text/css" rel="stylesheet" href="onglets.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="onglets.js"></script>
</head>
<body>
<!--------------------->
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>
<!--------------------->
</body>
</html>
Ouvrez aussi un fichier vide "onglets.css"
On va construire, ensemble, étape par étape ces onglets.
On veut d'abord obtenir exactement ceci:
Ajoutez l'image de fond suivante à body:
texture-grise.jpg :
Changez la couleur du texte des lignes de la liste en blanc.
Utilisez "float: left;" pour que lignes s'affichent de gauche à droite (et pas de haut en bas)
Utilisez "list-style: none;" sur la liste pour enlever les puces.
On utilise une astuce un peu compliquée pour obtenir le coin coupé :
C'est un dégradé (gradient) penché à 220 degrés avec un passage très court entre transparent et rouge:
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
Dans chaque onglet, ajoutez un peu d'espace entre le texte et les bords de l'onglet.
Rappel:
onglets.css
body
{
background-image: url(texture-grise.jpg);
}
#onglets-menu
{
list-style: none;
}
#onglets-menu li
{
float: left;
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
color: white;
padding: 11px 30px;
}
On veut maintenant obtenir exactement ceci:
Texte : Dans chaque onglet, utilisez la police suivante:
font-family: 'Lucida sans', Arial, Helvetica;
Mettez le texte en gras et ajustez sa taille à 12px.
Ajoutez une légère ombre sous le texte (text-shadow).
Relief : Pour l'effet de relief entre les onglets, ajoutez une ombre (voir box-shadow) semi-transparente rgba(0, 0, 0, .2) positionnée à gauche .
menu-actif: Faites en sorte que l'onglet ayant class="menu-actif" soit affiché en blanc.
(pour garder le coin coupé, reprenez la même idée que les autres onglets, en remplaçant la couleur dans le gradient par blanc)
La couleur du texte de l'onglet actif est #333 et il faut lui enlever l'ombre, avec : "text-shadow: none;"
:hover On veut changer légèrement la couleur d'un onglet quand la souris lui passe par-dessus.
Pour ça, on reprend la même idée que les coins coupés des autres onglets, en remplaçant la couleur dans le gradient par #c93434
onglets.css
body
{
background-image: url(texture-grise.jpg);
}
#onglets-menu
{
list-style: none;
}
#onglets-menu li
{
float: left;
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
color: white;
padding: 11px 30px;
font-family: 'Lucida sans', Arial, Helvetica;
font-weight: bold;
font-size: 12px;
text-shadow: 0 1px 0 rgba(0,0,0,.5);
box-shadow: -4px 0 0 rgba(0, 0, 0, .2);
}
#onglets-menu li:hover
{
background: linear-gradient(220deg, transparent 10px, #c93434 11px);
}
#onglets-menu .menu-actif
{
background: linear-gradient(220deg, transparent 10px, white 11px);
color: #333;
text-shadow: none;
}
/* Forcer à rester blanc quand la souris passe sur le menu actif */
#onglets-menu .menu-actif:hover
{
background: linear-gradient(220deg, transparent 10px, white 11px);
}
On a fini la partie "menu" des onglets. Il nous reste à faire le contenu.
Utilisez cette nouvelle version du fichier onglets.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>onglets</title>
<link type="text/css" rel="stylesheet" href="onglets.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="onglets.js"></script>
</head>
<body>
<!--------------------->
<div id="onglets">
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>
<div id="onglets-contenu">
<div>Martien est un nom générique qui désigne plusieurs types de créatures imaginaires censées vivre sur Mars. Selon la version la plus répandue, les martiens, également nommés « petits hommes verts », sont des êtres à l'apparence vaguement humanoïde et repoussante, minces, avec une grosse tête et des yeux globuleux, généralement animés de mauvaises intentions envers l'espèce humaine. Le nom de martien est souvent devenu, à tort, synonyme d'extraterrestre dans la culture populaire.</div>
<div class="contenu-actif"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
<div>Le chocolat [ ʃɔkɔla ], terme d'origine mésoaméricaine, est un aliment sucré produit à partir de la fève de cacao. Celle-ci est fermentée, torréfiée, broyée jusqu'à former une pâte de cacao liquide dont on extrait la matière grasse appelée beurre de cacao. Le chocolat est constitué du mélange, dans des proportions variables, de pâte de cacao, de beurre de cacao et de sucre ; on y ajoute éventuellement des épices, comme la vanille, ou des matières grasses végétales.</div>
<div><ul><li>Moi: beaucoup</li><li>Eux: pas tant que ça</li></ul></div>
</div>
</div>
<!--------------------->
</body>
</html>
(Dans les pages suivantes, le HTML est encore fixé. Vous ne devez pas le changer. Vous pouvez uniquement modifier le CSS.)
Regardons d'abord comment est structuré cet HTML :
<body>
<div id="onglets">
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>
<div id="onglets-contenu">
<div>Martien est un nom générique ...</div>
<div class="contenu-actif">Lorem ipsum dolor sit...</div>
<div>Le chocolat [ ʃɔkɔla ], terme d'origine...</div>
<div>...</div>
</div>
</div>
</body>
On veut obtenir ceci:
Pour s'assurer que <div id="onglets-contenu"> s'affiche après les menus (qui sont float) ajoutez-lui "clear: both;".
On veut réduire la largeur de l'ensemble et le centrer. Pour ça:
Fixez le width de <div id="onglets"> à 600 pixels.
Utilisez margin auto à gauche et à droite pour le centrer.
On veut que "onglets-contenu" soit blanc.
Remarquez que "onglets-menu" n'est pas collé à gauche.
En effet, par défaut un <ul> a du padding à gauche. Il faut l'enlever.
Dernière étape. On veut obtenir ceci:
Pour l'instant, tous les <div> dans "onglets-contenu" sont montrés en même temps.
On voudrait les cacher (display: none;) par défaut.
Ensuite, on voudrait montrer (display: block;) un seul, celui qui a class="contenu-actif" .
Complétez tout ce qu'il manque pour obtenir l'affichage ci-dessus.
/* Fortement inspiré de :
* http://red-team-design.com/css3-tabs-with-beveled-corners/
*/
body
{
background-image: url(texture-grise.jpg);
font-family : sans;
}
#onglets
{
width: 600px;
margin: 2em auto;
}
#onglets-menu
{
list-style: none;
padding: 0;
}
#onglets-menu li
{
float: left;
background: linear-gradient(220deg, transparent 10px, #ad1c1c 11px);
color: white;
padding: 11px 30px;
font-family: 'Lucida sans', Arial, Helvetica;
font-weight: bold;
font-size: 12px;
text-shadow: 0 1px 0 rgba(0,0,0,.5);
box-shadow: -4px 0 0 rgba(0, 0, 0, .2);
cursor: pointer;
}
#onglets-menu li:hover
{
background: linear-gradient(220deg, transparent 10px, #c93434 11px);
}
#onglets-menu .menu-actif
{
background: linear-gradient(220deg, transparent 10px, white 11px);
color: #333;
text-shadow: none;
}
/* Forcer à rester blanc quand la souris passe sur le menu actif */
#onglets-menu .menu-actif:hover
{
background: linear-gradient(220deg, transparent 10px, white 11px);
}
#onglets-contenu
{
clear: both;
background-color: white;
border-radius: 0 2px 2px 2px;
box-shadow: 0 2px 2px #000;
}
#onglets-contenu>div
{
display: none;
padding: 30px;
}
#onglets-contenu>.contenu-actif
{
display: block;
}
#onglets-contenu>div>*:first-child
{
margin-top: 0;
}
onglets.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>onglets</title>
<link type="text/css" rel="stylesheet" href="onglets.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="onglets.js"></script>
</head>
<body>
<!--------------------->
<div id="onglets">
<ul id="onglets-menu">
<li>Présentation</li>
<li class="menu-actif">Règles</li>
<li>Personnages</li>
<li>Scores</li>
</ul>
<div id="onglets-contenu">
<div>Martien est un nom générique qui désigne plusieurs types de créatures imaginaires censées vivre sur Mars. Selon la version la plus répandue, les martiens, également nommés « petits hommes verts », sont des êtres à l'apparence vaguement humanoïde et repoussante, minces, avec une grosse tête et des yeux globuleux, généralement animés de mauvaises intentions envers l'espèce humaine. Le nom de martien est souvent devenu, à tort, synonyme d'extraterrestre dans la culture populaire.</div>
<div class="contenu-actif"><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. <p><p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>
<div>Le chocolat [ ʃɔkɔla ], terme d'origine mésoaméricaine, est un aliment sucré produit à partir de la fève de cacao. Celle-ci est fermentée, torréfiée, broyée jusqu'à former une pâte de cacao liquide dont on extrait la matière grasse appelée beurre de cacao. Le chocolat est constitué du mélange, dans des proportions variables, de pâte de cacao, de beurre de cacao et de sucre ; on y ajoute éventuellement des épices, comme la vanille, ou des matières grasses végétales.</div>
<div><ul><li>Moi: beaucoup</li><li>Eux: pas tant que ça</li></ul></div>
</div>
</div>
<!--------------------->
</body>
</html>
Nos onglets s'affichent bien. On ne va plus toucher aux fichiers HTML et CSS.
On veut maintenant passer d'un onglet à l'autre à l'aide d'un petit programme en JavaScript.
Dans les pages suivantes, on va le faire, ensemble, en deux étapes :
$('span').click(function(e){...});
La fonction anonyme function(e){...} est appelée « gestionnaire d'événements » : son rôle est de réagir lorsqu'un événement survient.
Sur quel(s) élément(s) peut-on cliquer pour provoquer l'appel de la fonction gestionnaire d'événements ?Quelles élément(s) se trouvent dans la liste jQuery suivante ?
$('img')
$('img').click(function(e){...});On peut installer un gestionnaire d'événements sur plusieurs éléments en même temps.
Rappel:
un élément peut avoir plusieurs valeurs dans class, séparées par des espaces:
<p class="actu exemple autre-exemple">...</p>
jQuery fourni les fonctions .addClass() et .removeClass() pour ajouter et enlever des noms dans "class".
.hasClass() permet de voir si un nom se trouve dans les valeurs de class.
Pour des affichages complexes, il est préférable d'utiliser "class" que .css(). En utilisant class on écrit uniquement le CSS dans des fichiers CSS. C'est plus propre / lisible.
Quand un événement survient, notre fonction est appelé. Elle reçoit deux informations importantes:
- "event" (en argument): un objet décrivant l'événement, avec des informations comme la position de la souris, le bouton de souris utilisé, la touche appuyée ... On peut omettre cet argument si on n'en a pas besoin.
- "this" : l'objet associé à cette fonction. C'est l'élément DOM sur lequel est survenu l'événement. Dans cet exemple c'est h1. Attention: "this" est un objet DOM. Pour l'utiliser plus facilement, on peut le transformer en liste jQuery : $(this)
C'est à vous !
En vous inspirant de la structure de tous les fichiers JS vus jusqu'à maintenant, écrivez le code nécessaire pour faire fonctionner le menu (c'est à dire, uniquement la partie d'en haut).
Lorsque l'utilisateur clique sur un onglet on doit:
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
$('#onglets-menu li').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$('.menu-actif').removeClass('menu-actif');
$(this).addClass('menu-actif');
});
console.log("La mise en place est finie. En attente d'événements...");
});
on a utilisé "mousedown" au lieu de "click".
Passons maintenant à la partie du bas (contenu).
C'est un peu plus compliqué.
Dans cet exemple, l'utilisateur a cliqué sur un onglet.
Grâce
à « this », on a l'élément cliqué. On a donc pu faire : $(this).addClass('menu-actif');
Mais on n'a pas le <div> contenu
correspondant (pour lui ajouter la classe "contenu-actif")
La solution est de :
On va faire ça ensemble.
$('li') contient tous les li de la page, pas uniquement ceux du menu.
On voudrait se limiter à ceux du menu uniquement.
Ici, on veut une liste jQuery contenant les 4 <li> qui sont dans <ul id="onglets-menu">
onglets.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
$('#onglets-menu li').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$('.menu-actif').removeClass('menu-actif');
$(this).addClass('menu-actif');
var num=$('#onglets-menu>li').index(this);
console.log("L'utilisateur a cliqué sur l'onglet:",num);
});
console.log("La mise en place est finie. En attente d'événements...");
});
onglets.js
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
$('#onglets-menu li').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$('.menu-actif').removeClass('menu-actif');
$(this).addClass('menu-actif');
$('.contenu-actif').removeClass('contenu-actif');
var num=$('#onglets-menu>li').index(this);
$('#onglets-contenu>div').eq(num).addClass('contenu-actif');
});
console.log("La mise en place est finie. En attente d'événements...");
});
On veut afficher un tableau 3x3
Quand l'utilisateur clique sur une case, un "X" est ajouté.
Pour l'instant on ajoute uniquement des "X", on s'occupera des "O" après.
Écrivez le HTML le CSS et le JS nécessaire pour obtenir exactement le résultat voulu.
C'est à vous. (Correction à la page suivante)
HTML:
<table id="morpion">
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>
CSS:
#morpion
{
border-collapse: collapse;
}
#morpion td
{
border: 1px solid black;
width: 40px;
height: 40px;
font-size: 30px;
text-align: center;
cursor: pointer;
}
#morpion td:hover
{
background-color: #ffc;
}
JS:
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
$('#morpion td').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
$(this).text('X');
});
console.log("La mise en place est finie. En attente d'événements...");
});
On veut maintenant que 2 joueurs puissent cliquer, chacun leur tour.
On va donc ajouter une variable joueur. Elle peut valoir "X" ou "O".
JS:
$(document).ready(function()
{
var joueur="X";
$('#morpion td').mousedown(function()
{
// ici on peut utiliser joueur !!!
...
});
});
joueur est déclaré en dehors de la fonction (2) passée à mousedown, mais on peut quand même l'utiliser dedans.
Ça peut paraître simple ou bête, mais c'est une particularité importante du JavaScript qui est très utilisée.
Une fonction qui utilise une variable définie dans une autre fonction extérieure est appelée une fermeture ("closure" en anglais).
En réfléchissant bien, vous vous rendrez compte que c'est plus compliqué qu'il ne semble:
fonction (2) doit se souvenir que joueur est une variable définie dans une autre fonction...
On verra tout ça, plus tard, en détail.
En utilisant joueur, faites en sorte que les 2 joueurs puissent cliquer chacun leur tour.
S'ils cliquent sur une case où il y a déjà quelque-chose, rien ne doit se passer.
JS:
console.log("Ce programme JS vient d'être chargé");
$(document).ready(function()
{
console.log("Le document est pret");
var joueur="X";
$('#morpion td').mousedown(function()
{
console.log("Le bouton de la souris a été enfoncé.");
if($(this).text()!==''){return;}
$(this).text(joueur);
joueur=(joueur==="X" ? 'O' : 'X');
});
console.log("La mise en place est finie. En attente d'événements...");
});