Attributs dynamiques
Introduction
Dans une page web, les attributs HTML ne sont pas toujours figés :
- un bouton peut être activé ou désactivé selon l'état du panier,
- un lien peut changer de destination selon la langue choisie,
- un message peut changer d"apparence, par exemple s'afficher en rouge en cas d'erreur ou en vert quand tout va bien.
- ...
La directive v-bind permet de relier un attribut HTML aux données réactives de l'application ou à une expression qui en dépend. L'attribut est alors mis à jour automatiquement dès que ces données changent.
La directive v-bind
La directive v-bind relie un attribut HTML à une donnée réactive. Ainsi, l'attribut s'actualise automatiquement dès que la valeur change dans l'application.
Elle permet de gérer différents types d'attributs. On peut ainsi contrôler des attributs booléens comme disabled, required ou checked, mettre à jour des attributs littéraux tels que href ou aria-*, et manipuler des attributs spéciaux comme class et style, pour lesquels Vue offre des syntaxes avancées.
On l'utilise en écrivant v-bind: suivi du nom de l'attribut HTML. Par exemple, pour relier l'attribut disabled à une expression Javascript, on écrit : v-bind:nomAttributHTML="expression Javascript...".
Dans l'exemple suivant, on utilise v-bind pour modifier dynamiquement la valeur de l'attribut href d'un lien en fonction d'une variable. On emploie une condition ternaire pour choisir l'URL à appliquer.
<script setup>
import { ref } from 'vue';
const estConnecte = ref(true);
</script>
<template>
<!-- Lien différent selon l'état de connexion -->
<a v-bind:href="estConnecte ? '/profil' : '/connexion'">
Accéder
</a>
</template>
Ici, si la variable estConnecte vaut true, le lien dirige vers la page de profil. Sinon, il renvoie vers la page de connexion. Comme la valeur de estConnecte est réactive (ref()), Vue met à jour l'attribut automatiquement dès que la valeur change.
Attributs standards
Attributs littéraux
Certains attributs HTML, comme href, lang ou title, attendent une chaîne de caractères comme valeur. Avec Vue, on peut les relier à une expression JavaScript, ce qui permet de générer dynamiquement cette chaîne. Ainsi, la valeur de l'attribut se met automatiquement à jour lorsque les données de l'application changent.
Exemple : afficher l'image d'un produit selon la couleur choisie
<script setup>
import { ref } from 'vue';
const couleur = ref('rose');
</script>
<template>
<h2>Modifier une partie de la source de l'image</h2>
<button type="button" @click="couleur = 'rose'">Rose</button>
<button type="button" @click="couleur = 'vert'">Vert</button>
<img
v-bind:src="`/images/casque-${couleur}.png`"
alt=""
width="120"
>
</template>
<style scoped>
img {
display: block;
width: 120px;
height: 120px;
}
/* Prouve que l'attribut src de l'image a bien été modifié */
img[src*='rose'] {
background-color: pink;
}
img[src*='vert'] {
background-color: YellowGreen;
}
</style>
Ici, l'attribut src dépend directement de la variable couleur (src="`/images/casque-${couleur}.png`"). Quand on clique sur un bouton, la valeur de couleur change (rose ou vert), et l'image affichée se met à jour automatiquement. C'est un cas très courant dans les interfaces (ex.: un sélecteur de variantes de produit, un thème clair/sombre avec une icône différente, etc).
Attributs booléens
Les attributs booléens comme disabled, required ou hidden attendent une valeur de type booléen. Avec Vue, on peut les relier à une expression JavaScript : l'attribut est ajouté si l'expression vaut true (ou une chaîne vide) et il est retiré si l'expression vaut false.
Par exemple, pour désactiver le bouton "Passer commande" quand le panier est vide :
<script setup>
import { ref } from 'vue';
// Ici on utilise 'ref()' car on réassigne sa valeur dans 'viderPanier'.
// Cependant, on aurait pu utiliser 'reactive()' et utiliser l'instruction suivante
// pour vider le panier plutot que de lui réassigner une valeur : panier.length = 0.
const panier = ref([
{ id: 1, libelle: 'Casque', qte: 5 },
{ id: 2, libelle: 'Câble', qte: 3 }
])
const viderPanier = () => { panier.value = [] }
</script>
<template>
<p>Articles dans le panier : {{ panier.length }}</p>
<button type="button" v-bind:disabled="panier.length === 0">Passer commande</button>
<button type="button" @click="viderPanier">Vider le panier</button>
</template>
Dans l'exemple précédent, l'expression Javascript panier.length === 0 liée à l'attribut HTML disabled vérifie si le tableau panier est vide. Lorsque l'expression panier.length === 0 est évaluée à true, l'attribut disabled est ajouté au bouton. Si l'expression est évaluée à false, l'attribut n'est pas ajouté.
Simplifier l'écriture avec la syntaxe raccourcie
Il existe une écriture plus concise que v-bind en toutes lettres. On peut placer directement le signe : devant le nom de l'attribut. Par exemple, au lieu d'écrire v-bind:disabled="estDesactive", on note :disabled="estDesactive".
<script setup>
import { ref } from 'vue';
const estDesactive = ref(true);
</script>
<template>
<button :disabled="estDesactive">Envoyer</button>
</template>
Enfin, si l'expression JavaScript se limite à une variable dont le nom est identique à celui de l'attribut HTML, on peut simplifier encore davantage. On omet complètement la valeur et on indique seulement l'attribut précédé de :. Par exemple, si une variable disabled vaut true ou false, au lieu d'écrire :disabled="estDesactive", on peut simplement écrire :disabled. Vue associe automatiquement l'attribut à la donnée réactive du même nom.
<script setup>
import { ref } from 'vue';
const disabled = ref(true);
</script>
<template>
<button :disabled>Envoyer</button>
</template>
Attributs spéciaux :class et :style
Pour les attributs standards vus précédemment, l'expression doit renvoyer une valeur adaptée :
- un booléen pour les attributs booléens comme disabled;
- une chaîne de caractères pour les attributs classiques comme href.
Les liaisons avec class et style sont plus flexibles car elles acceptent non seulement une chaîne de caractères, mais aussi une expression qui retourne un objet ou un tableau. Ces syntaxes permettent de gérer plusieurs classes ou propriétés CSS en une seule fois.
L'attribut :class sert principalement à modifier les classes CSS selon l'état d'un élément. L'attribut :style permet notamment de définir directement des valeurs CSS calculées ou modifiées par JavaScript.
Attribut :class
Syntaxe simple (chaîne de caractères)
<script setup>
import { ref } from 'vue';
const estActif = ref(true);
</script>
<template>
<button class="btn" :class="estActif ? 'btn-primary' : 'btn-secondary'">
Valider
</button>
</template>
Ici, la valeur de :class ne remplace pas celle de l'attribut HTML class, elle vient s'y ajouter. La classe CSS btn est donc toujours appliquée, tandis que Vue choisit btn-primary ou btn-secondary selon la valeur de estActif.
Syntaxe objet
Avec la syntaxe objet, chaque clé est un nom de classe et la valeur associée est une condition. Si l'expression est évaluée à true, la classe est présente. Dans le cas contraire, elle est absente. Cette syntaxe permet de gérer plusieurs classes indépendamment.
<script setup>
import { ref } from 'vue';
const estActif = ref(true);
const aErreur = ref(false);
</script>
<template>
<button :class="{ actif: estActif, 'text-danger': aErreur }">
Envoyer
</button>
</template>
Dans cet exemple, la classe CSS actif est appliquée car estActif vaut true. En revanche, la classe text-danger n'est pas appliquée car aErreur vaut false. Si les deux conditions sont vraies, les deux classes sont ajoutées.
On remarque aussi que la clé actif est écrite sans guillemets, tandis que text-danger doit être entourée de guillemets. En effet, un nom de propriété contenant un tiret ou un autre caractère non autorisé dans un identifiant JavaScript doit être placé entre guillemets.
Syntaxe tableau
La syntaxe tableau permet de combiner plusieurs types d'expressions dans une seule liaison, notamment des classes fixes, des chaînes construites dynamiquement et des objets conditionnels.
<script setup>
import { ref } from 'vue';
const variante = ref('primaire');
const chargement = ref(false);
</script>
<template>
<button :class="['btn', 'btn-' + variante, { 'btn-loading': chargement }]">
Enregistrer
</button>
</template>
Ici, la classe CSS btn est toujours appliquée. L'expression 'btn-' + variante construit le nom de la classe selon la variante choisie. Enfin, l'objet conditionnel ajoute btn-loading uniquement lorsque chargement vaut true. Le tableau est particulièrement utile lorsqu'on doit regrouper ces différentes expressions. S'il n'y a qu'une classe fixe et une condition, l'association de class et de :class reste généralement plus simple.
Attribut :style
Syntaxe simple (chaîne de caractères)
<script setup>
import { ref } from 'vue';
const estImportant = ref(true);
</script>
<template>
<p style="margin: 10px" :style="estImportant ? 'color: red; font-weight: bold' : 'color: gray'">
Attention
</p>
</template>
La valeur de :style ne remplace pas les styles définis dans l'attribut HTML style, elle les complète. Ici, la marge margin: 10px est toujours appliquée. Selon la valeur de estImportant, Vue applique soit un texte rouge et gras, soit un texte gris. Cette syntaxe est simple, mais devient moins pratique lorsque plusieurs propriétés reçoivent des valeurs dynamiques distinctes.
Syntaxe objet
Avec la syntaxe objet, chaque clé correspond à une propriété CSS et la valeur associée définit son style. Cette écriture est particulièrement utile lorsque les valeurs CSS doivent être déterminées dynamiquement, plutôt que de simplement choisir entre des apparences prédéfinies.
<script setup>
import { ref } from 'vue';
const couleur = ref('blue');
const taille = ref(18);
</script>
<template>
<p class="apercu" :style="{ color: couleur, fontSize: taille + 'px' }">
Aperçu du texte
</p>
</template>
<style scoped>
.apercu {
padding: 20px;
border: 1px solid black;
}
</style>
Ici, color reçoit directement la valeur de couleur, tandis que fontSize utilise la valeur de taille à laquelle on ajoute l'unité px. Si ces données réactives changent, Vue actualise automatiquement les styles concernés. Les règles permanentes, comme l'espacement et la bordure, restent dans la feuille CSS du composant.
Pour les noms de propriétés composés, il est recommandé d'utiliser la notation camelCase comme en JavaScript classique (par exemple fontSize au lieu de font-size). Vous pouvez néanmoins conserver l'écriture CSS habituelle en entourant la clé de guillemets simples (par exemple 'font-size').
Syntaxe tableau
La syntaxe tableau permet de fusionner plusieurs objets de styles existants dans une seule expression. Si plusieurs objets définissent la même propriété CSS, la valeur du dernier objet est prioritaire. Les styles permanents restent, quant à eux, dans le CSS du composant.
<script setup>
import { ref } from 'vue';
const styleUtilisateur = ref({
color: 'blue',
fontSize: '18px'
});
const contrasteEleve = ref(true);
const styleContraste = {
color: 'black',
backgroundColor: 'white'
};
</script>
<template>
<p class="apercu" :style="[styleUtilisateur, contrasteEleve ? styleContraste : {}]">
Aperçu personnalisable
</p>
</template>
<style scoped>
.apercu {
padding: 20px;
border: 1px solid black;
}
</style>
Vue fusionne les objets du tableau pour appliquer les styles finaux. styleUtilisateur définit la couleur et la taille initiales du texte. Lorsque contrasteEleve vaut true, styleContraste est également appliqué. Comme il apparaît en dernier, sa propriété color remplace celle du premier objet. La taille du texte, qui n'est pas redéfinie, est conservée.
Si contrasteEleve vaut false, l'expression conditionnelle renvoie un objet vide et aucun style supplémentaire n'est ajouté. Dans une application réelle, un mode de contraste prédéfini serait généralement géré avec :class. Cet exemple illustre surtout l'intérêt du tableau lorsqu'il faut fusionner des objets de styles existants.
Bonnes pratiques
Privilégiez le CSS classique pour les styles permanents et :class pour basculer entre des apparences prédéfinies. Réservez :style aux situations dans lesquelles JavaScript doit déterminer directement les valeurs CSS.
Les tableaux sont des possibilités supplémentaires, pas des obligations. Utilisez-les lorsque plusieurs classes ou plusieurs objets de styles doivent réellement être combinés. La syntaxe la plus simple qui répond au besoin reste généralement la meilleure.
Objet d'attributs avec v-bind
Il est aussi possible de construire directement un objet d'attributs à l'intérieur du <template>. Dans cet exemple, les valeurs des attributs sont définies selon l'état réactif de la variable externe. Le bouton permet de basculer entre un lien interne et un lien externe, ce qui met en évidence le comportement dynamique de v-bind lorsqu'il reçoit un objet complet.
<script setup>
import { ref } from 'vue';
const externe = ref(true);
const basculer = () => { externe.value = !externe.value };
</script>
<template>
<a class="btn" v-bind="{
// null, undefined ou false retirent l'attribut de l'élément.
href: externe ? 'https://exemple.com' : '/conditions',
target: externe ? '_blank' : null,
rel: externe ? 'noopener noreferrer' : null,
title: externe ? 'Ouvre dans un nouvel onglet' : 'Conditions'
}">Conditions</a>
<button type="button" @click="basculer">Basculer interne/externe</button>
<p>Externe : {{ externe }}</p>
</template>
L'utilité de v-bind ne s'arrête pas aux attributs HTML. On peut aussi l'utiliser directement dans le bloc <style> d'un composant afin de relier des règles CSS aux données de l'application. Cette fonctionnalité sera abordée dans un chapitre ultérieur consacré aux styles dans les composants Vue.
Exercice 01 : Lien Contact multilingue avec attribut href dynamique
Objectif : Lorsque l'utilisateur choisit une langue ("fr" ou "en"), le lien "Contact" s'adapte et ouvre la page correspondante (/fr/contact ou /en/contact). Le texte du lien reste identique, seule la destination change immédiatement selon la langue active.
Instructions :
- Dans la partie <script setup>, importer la dépendance ref depuis Vue.
- Créer une constante réactive nommée langue initialisée à la chaîne fr via ref().
-
Créer deux fonctions pour changer la langue courante :
- activerFr() qui assigne fr à langue.value.
- activerEn() qui assigne en à langue.value.
- Dans la partie <template>, créer un sous-titre <h2> avec le texte "Exo 01".
- Afficher un paragraphe indiquant la langue active à l'aide de moustaches, par exemple "Langue : [langue]".
-
Créer deux boutons pour changer la langue :
- Un bouton "FR" qui appelle la fonction activerFr() au clic.
- Un bouton "EN" qui appelle la fonction activerEn() au clic.
- Créer un lien "Contact" et relier son attribut href avec la directive v-bind afin qu'il pointe vers /fr/contact ou /en/contact selon la valeur de la constante langue.
-
Tester :
- Cliquer sur "FR" puis sur "EN" et vérifier que l'attribut href du lien change en conséquence.
- Vérifier la destination affichée par le navigateur. Tester la navigation uniquement si les pages de destination existent dans le projet.
Exercice 02 : Voter une fois et désactiver le bouton
Objectif : Permettre à l'utilisateur de voter une seule fois puis empêcher tout second clic pour éviter les doublons. Après le premier clic sur "Voter", l'interface confirme l'action et le bouton reste inactif tant que l'état du composant est conservé. Il s'agit d'une simulation côté navigateur, pas d'un système de vote sécurisé.
Instructions :
- Dans la partie <script setup>, importer la dépendance ref depuis Vue.
- Créer une constante réactive nommée aVote initialisée à false via ref().
- Créer une fonction enregistrerVote() qui assigne la valeur true à aVote.value. Ne pas prévoir de fonction inverse afin que l'action reste définitive tant que la page n'est pas rechargée.
- Dans la partie <template>, créer un sous-titre <h2> avec le texte "Exo 02".
-
Créer un bouton "Voter" qui :
- appelle la fonction enregistrerVote() au clic via la directive d'événement v-on,
- voit son attribut disabled relié à la constante aVote pour empêcher tout second clic après le premier,
- affiche un style visuel adapté lorsqu'il est désactivé (ex. classe fixe "btn").
- Sous le bouton, afficher un message de confirmation avec la directive v-if lorsque la constante aVote vaut true (ex. : "Merci pour votre vote").
-
Tester :
- Cliquez une première fois sur "Voter" et vérifier que le bouton devient inactif immédiatement.
- Essayer de recliquer et vérifier que l'action est bloquée grâce à l'attribut disabled.
- Vérifier que le message de confirmation s'affiche après le premier clic.
Exercice 03 : Badge simple avec classe statique et classe dynamique
Objectif : L'utilisateur choisit un niveau d'information ("info", "success", "error") et l'interface affiche un badge dont l'apparence s'adapte à ce choix pour signaler clairement le type de message, tout en conservant un style de base identique. Le contenu du badge ne change pas, seule sa présentation varie pour refléter le niveau sélectionné. Si aucun niveau n'est choisi, le badge reste dans un style neutre.
Instructions :
- Dans la partie <script setup>, importer ref depuis Vue.
- Créer une constante réactive niveau initialisée à une chaîne vide via ref().
- Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 03".
-
Créer un libellé et une liste déroulante reliée à la constante réactive
niveau avec v-model.
Dans la liste, créer ces options :
- Première option : valeur vide pour l'attribut value et "— choisir —" en contenu textuel.
- Seconde option : "info" pour l'attribut value et "Info" en contenu textuel.
- Troisième option : "success" pour l'attribut value et "Succès" en contenu textuel.
- Quatrième option : "error" pour l'attribut value et "Erreur" en contenu textuel.
-
Sous la liste, ajouter un paragraphe qui affiche un texte (ex. : "Message").
Lui attribuer une classe statique "badge" via l'attribut HTML class.
Ajouter en plus une classe dynamique via :class qui dépend de la valeur de
niveau afin d'appliquer l'une des classes suivantes :
- "badge--info"
- "badge--success"
- "badge--error"
-
Dans la partie <style>, définir un CSS minimal :
- Une classe de base .badge avec un léger bord, un peu de padding, un angle arrondi, un fond gris clair et le texte en noir.
- Trois classes variantes :
- .badge--info : Fond bleu clair et texte bleu foncé.
- .badge--success : Fond vert clair et texte vert foncé.
- .badge--error : Fond rouge clair et texte rouge foncé.
-
Tester :
- Sélectionner chaque option et vérifier que l'élément conserve la classe statique "badge" et ajoute la bonne classe dynamique.
- Laisser la valeur vide et vérifier qu'aucune des classes dynamiques n'est ajoutée.
Exercice 04 : Carte produit avec classes dynamiques (syntaxe objet)
Objectif : Faire varier l'apparence d'une carte produit selon deux états cochés par l'utilisateur tout en gardant un style de base. La carte a toujours une classe statique, et ajoute ou retire des classes supplémentaires via :class écrit en syntaxe objet.
Instructions :
- Dans la partie <script setup>, importer ref depuis Vue.
-
Créer deux constantes réactives :
- enPromo initialisée à false via ref().
- enRupture initialisée à false via ref().
- Dans la partie <template>, ajouter un sous-titre <h2> avec le texte "Exo 04".
-
Créer deux contrôles reliés avec v-model :
- Une case à cocher pour "En promotion" liée à enPromo.
- Une case à cocher pour "En rupture" liée à enRupture.
- Sous les contrôles, créer un conteneur de carte produit (par exemple une balise <div> avec la classe statique "carte") contenant un titre et un court paragraphe.
-
Sur ce conteneur, utiliser :class avec la syntaxe objet pour ajouter des classes CSS selon l'état :
- Ajouter "carte--promo" lorsque enPromo vaut true.
- Ajouter "carte--rupture" lorsque enRupture vaut true.
-
Dans la partie <style>, écrire un CSS minimal :
- Classe de base "carte" avec un léger bord, du padding et un arrondi.
- Classe "carte--promo" qui met en évidence la promotion (par exemple bord ou fond vert).
- Classe "carte--rupture" qui atténue visuellement la carte (par exemple opacité réduite ou titre barré).
-
Tester :
- Cocher uniquement "En promotion" et vérifier que seule la classe "carte--promo" s'ajoute en plus de "carte".
- Cocher uniquement "En rupture" et vérifier que seule la classe "carte--rupture" s'ajoute en plus de "carte".
- Cocher les deux cases et vérifier que les deux classes sont présentes simultanément.
- Décocher toutes les cases et vérifier le retour au style de base.
Exercice 05 : Carte d'annonce personnalisable avec :class (syntaxe tableau)
Objectif : Créer une carte d'annonce dont l'apparence dépend de deux choix de l'utilisateur. Une liste déroulante permet de choisir un type d'annonce (standard ou premium) et une case à cocher permet de la mettre en avant. La carte conserve sa présentation de base et combine les autres classes grâce à :class en syntaxe tableau.
Instructions :
- Dans la partie <script setup>, importer ref depuis Vue.
-
Créer deux constantes réactives :
- variante initialisée à standard avec ref().
- miseEnAvant initialisée à false avec ref().
- Dans la partie <template>, créer un sous-titre <h2> avec le texte Exo 05.
-
Créer un libellé et une liste déroulante reliée à
variante avec
v-model. Prévoir deux options :
- La valeur standard, affichée sous le libellé Standard.
- La valeur premium, affichée sous le libellé Premium.
- Ajouter une case à cocher « Mettre en avant » reliée à miseEnAvant avec v-model.
-
Sous ces contrôles, créer une carte contenant un titre d'annonce et une courte description.
Sur son conteneur, utiliser :class avec un tableau
comportant trois éléments :
- La chaîne annonce, classe de base toujours appliquée.
- Une expression qui construit la classe annonce-standard ou annonce-premium en concaténant annonce- et la valeur de variante.
- Un objet conditionnel qui ajoute annonce-selectionnee lorsque miseEnAvant vaut true.
-
Dans la partie <style scoped>,
définir les classes CSS correspondantes :
- .annonce : bordure, espacement et angles arrondis.
- .annonce-standard : présentation neutre.
- .annonce-premium : bordure ou fond distinctif.
- .annonce-selectionnee : mise en évidence supplémentaire, par exemple un contour plus épais qui reste perceptible avec les deux variantes.
-
Tester :
- Choisir chaque variante et vérifier que la classe correspondante remplace l'autre.
- Cocher la case et vérifier que annonce-selectionnee s'ajoute sans retirer la variante.
- Décocher la case et vérifier que seule la classe de mise en avant est retirée.
- Dans les outils de développement, contrôler que annonce reste toujours présente.
Exercice 06 : Barre de progression avec :style et :class
Objectif : Créer une barre de progression dont la largeur s'adapte au pourcentage choisi par l'utilisateur. Sa couleur change en fonction de trois paliers : rouge en dessous de 33 %, orange de 33 % à 66 % et vert au-delà de 66 %. L'exercice permet de distinguer les valeurs CSS réellement dynamiques, gérées par :style, des apparences prédéfinies, gérées par :class.
Instructions :
- Dans la partie <script setup>, importer ref depuis Vue.
- Créer une constante réactive progression, initialisée à 0 avec ref(). Cette valeur représentera le pourcentage d'avancement.
- Dans la partie <template>, ajouter un sous-titre <h2> avec le texte Exo 06.
- Créer un <label> « Progression (0 à 100) » avec l'attribut for défini à prog. Le curseur à créer à l'étape suivante devra porter le même identifiant.
- Créer un curseur <input> de type range avec id="prog", un minimum de 0, un maximum de 100 et un pas de 1. Le relier à progression avec v-model.number.
- Afficher à proximité du curseur la valeur courante de progression suivie du symbole % à l'aide des moustaches. Le pourcentage doit rester lisible, indépendamment de la couleur de la barre.
- Créer un conteneur de barre avec une classe statique barre. À l'intérieur, placer une seconde balise <div> qui représente le remplissage et reçoit la classe statique remplissage.
- Sur le remplissage, utiliser :style avec la syntaxe objet pour définir la propriété width. Elle doit recevoir la valeur de progression suivie de %. Aide : la valeur peut être construite par concaténation, comme progression + '%'.
-
Toujours sur le remplissage, utiliser
:class avec la syntaxe objet
pour appliquer une classe de couleur selon la progression :
- remplissage--faible lorsque la progression est inférieure à 33.
- remplissage--moyenne lorsqu'elle est comprise entre 33 et 66 inclus.
- remplissage--elevee lorsqu'elle est supérieure à 66.
-
Dans la partie <style scoped>,
écrire les règles CSS permanentes et les variantes :
- .barre : une largeur adaptée, une hauteur fixe, un fond gris clair, des angles arrondis et overflow: hidden.
- .remplissage : occupe toute la hauteur de la barre et dispose d'une transition sur sa largeur.
- .remplissage--faible, .remplissage--moyenne et .remplissage--elevee : couleurs de fond rouge, orange et verte.
-
Tester :
- À 0 %, vérifier que le remplissage n'est pas visible.
- Déplacer le curseur et vérifier que la largeur suit précisément le pourcentage affiché.
- Tester les changements de couleur aux seuils 32 → 33 et 66 → 67.
- Tester 100 % et vérifier que la barre est entièrement remplie.
- Dans les outils de développement, vérifier que la largeur est définie par le style en ligne, tandis que la couleur provient d'une classe CSS.
Exercice 07 : Lien « Contacter le support » multicanal avec objet d'attributs
Objectif : Construire un lien « Contacter le support » dont la destination dépend du canal choisi par l'utilisateur : email, téléphone ou WhatsApp. Une fonction JavaScript construira un objet d'attributs HTML, appliqué en une seule fois avec v-bind. Aucun canal ne sera sélectionné au départ : le lien ne devra alors pas être activable.
Instructions :
- Dans la partie <script setup>, importer ref depuis Vue.
- Créer une constante réactive canal initialisée à une chaîne vide avec ref().
-
Créer trois constantes non réactives contenant des coordonnées fictives :
- emailSupport : support@exemple.com.
- telSupport : +32470123456.
- waSupport : 32470123456 (format international sans le signe + pour l'URL WhatsApp).
-
Créer une fonction obtenirContactAttrs()
qui renvoie un objet contenant les attributs du lien selon
canal.value.
Pour chaque canal, préparer les propriétés suivantes :
- href : une destination mailto: pour l'email, tel: pour le téléphone ou https://wa.me/ pour WhatsApp.
- target : _blank uniquement pour WhatsApp, sinon null.
- rel : noopener noreferrer uniquement pour WhatsApp, sinon null.
- title : un court texte décrivant l'action proposée, adapté au canal sélectionné.
- Dans la partie <template>, créer un sous-titre <h2> avec le texte Exo 07.
-
Créer un libellé et une liste déroulante reliée à
canal avec
v-model.
Prévoir quatre options :
- Une option vide affichée sous le texte — choisir —.
- La valeur email, affichée sous le texte Email.
- La valeur tel, affichée sous le texte Téléphone.
- La valeur whatsapp, affichée sous le texte WhatsApp.
- Afficher un paragraphe indiquant la valeur courante de canal avec les moustaches afin de faciliter les tests.
- Créer un lien « Contacter le support » avec une classe CSS fixe btn. Utiliser v-bind sans argument sur ce lien, en lui passant le résultat de la fonction obtenirContactAttrs(). Ainsi, toutes les propriétés de l'objet deviennent des attributs du lien.
- Ajouter un message d'aide avec v-if lorsque canal est vide, par exemple « Choisissez un canal pour activer le lien. ». Vérifier que, dans ce cas, la fonction renvoie bien href: null : un élément <a> sans attribut href ne permet pas de naviguer.
- Dans la partie <style scoped>, définir un style simple pour la classe .btn afin que le lien soit identifiable visuellement. Ne pas employer :style pour ces règles CSS permanentes.
-
Tester :
- Sans sélection, vérifier que le message d'aide apparaît et que le lien ne possède pas d'attribut href.
- Choisir Email et vérifier la présence d'un lien commençant par mailto:.
- Choisir Téléphone et vérifier la présence d'un lien commençant par tel:.
- Choisir WhatsApp et vérifier que href, target et rel sont adaptés.
- Revenir sur l'option vide et vérifier que le lien n'est plus activable.
- Contrôler les attributs dans les outils de développement sans envoyer de message aux coordonnées fictives de l'exercice.