L'attribut spécial ref de Vue.js permet d'obtenir une référence directe à un élément HTML du DOM ou à une instance de composant enfant une fois que celui-ci a été rendu. C'est un moyen essentiel d'interagir directement avec le DOM ou les composants de manière impérative, tout en respectant l'approche réactive de Vue. Il est important de noter que les références ne sont accessibles qu'après le montage initial du composant.
Trois cas d'utilisation principaux de ref :
- Sur un élément HTML standard : Lorsque
refest appliqué à un élément HTML (comme<div>,<input>,<h1>, etc.), vous pouvez récupérer l'élément DOM natif viathis.$refs.nomDeLaRef. Cela est utile pour des manipulations DOM directes qui ne sont pas gérées par la réactivité de Vue, comme le focus sur un champ, la mesure de dimensions, ou l'intégration avec des bibliothèques tierces. - Sur une instance de composant enfant : En ajoutant
refà un composant enfant personnalisé, vous obtenez une référence à l'instance de ce composant. Cela vous donne accès à toutes ses propriétés (data,computed,props) et méthodes déclarées dans l'instance du composant enfant. C'est particulièrement utile pour appeler des méthodes du composant enfant depuis son parent. - Avec des itérations
v-for: L'utilisation derefà l'intérieur d'une bouclev-forrend la référence un tableau contenant toutes les instances des éléments ou composants générés par la boucle. Si vous attribuez le même nom derefà chaque élément de la boucle,this.$refs.votreRefsera un tableau.
Points d'attention lors de l'utilisation de ref :
- Disponibilité de la référence : Les références ne sont pas disponibles immédiatement après la création de l'instance Vue. Elles sont remplies une fois que le composant a été monté. Par conséquent, accédez-y dans des hooks de cycle de vie comme
mounted()ou dans une fonction de rappelthis.$nextTick(() => {})pour vous assurer que le DOM est prêt. - Références dynamiques : Si vous utilisez une expression JavaScript pour définir le nom de votre
ref(par exemple,:ref="maVariableRef"), la référence sera accessible viathis.$refs[maVariableRef]. - Références multiples avec
v-for: Si unrefavec le même nom est appliqué à plusieurs éléments ou composants via unv-for,this.$refs.votreRefsera un tableau contenant toutes les références. Vous devrez itérer sur ce tableau ou y accéder par index pour cibler des éléments spécifiques. Si vous souhaitez des références individuelles pour chaque élément dans unv-for, assurez-vous de générer des noms derefuniques (par exemple,:ref="'item-' + index").
Exemples pratiques
Exemple 1 : Accès à un élément DOM et à une instance de composant
Cet exemple montre comment obtenir une référence à un élément <h2> pour modifier son contenu et son style, ainsi qu'à un composant enfant pour interagir avec ses données et méthodes.
<div id="app-refs-demo">
<h2 ref="titrePrincipal">Bonjour les références Vue !</h2>
<!-- Composant enfant défini globalement pour cet exemple -->
<composant-enfant ref="instanceComposant"></composant-enfant>
<button @click="interagirAvecRefs">Interagir avec les Refs</button>
</div>
<script>
// Définition globale du composant enfant pour la démo
Vue.component('composant-enfant', {
template: `
<div style="border: 1px solid #ccc; padding: 10px; margin-top: 10px;">
<p>Message de l'enfant: <strong>{{ messageInterne }}</strong></p>
<button @click="emetEvenement">Bouton enfant</button>
</div>
`,
data() {
return {
messageInterne: "Je suis un composant enfant."
};
},
methods: {
saluer() {
alert('Bonjour depuis le composant enfant !');
},
modifierMessage(nouveauMsg) {
this.messageInterne = nouveauMsg;
},
emetEvenement() {
console.log("L'enfant a émis un événement.");
}
}
});
new Vue({
el: '#app-refs-demo',
methods: {
interagirAvecRefs() {
// Accéder et modifier un élément DOM via sa ref
if (this.$refs.titrePrincipal) {
this.$refs.titrePrincipal.innerText = "Texte du titre modifié !";
this.$refs.titrePrincipal.style.color = 'blue';
console.log("Texte du H2 :", this.$refs.titrePrincipal.innerText);
}
// Accéder et interagir avec une instance de composant enfant via sa ref
if (this.$refs.instanceComposant) {
console.log("Message de l'enfant :", this.$refs.instanceComposant.messageInterne);
this.$refs.instanceComposant.saluer();
this.$refs.instanceComposant.modifierMessage("Nouveau message de l'enfant, défini par le parent !");
}
}
},
mounted() {
console.log("Les refs sont disponibles après le montage.");
}
});
</script>
Exemple 2 : Utilisation d'une ref avec un composant d'interface utilisateur (UI)
Souvent, les bibliothèques de composants UI (comme Element UI, Vuetify) exposent des méthodes que vous pouvez appeler sur leurs instances. ref est le moyen privilégié pour y accéder.
<template>
<div>
<!-- Imaginons un composant de tableau personnalisé "mon-tableau-de-donnees" -->
<!-- Il expose une méthode "reinitialiserTri" -->
<mon-tableau-de-donnees ref="listeArticles" :donnees="dataItems"></mon-tableau-de-donnees>
<button @click="effacerLeTri">Effacer le tri du tableau</button>
</div>
</template>
<script>
// Définition d'un composant mock pour 'mon-tableau-de-donnees'
// En réalité, ce serait un composant importé ou de librairie UI
Vue.component('mon-tableau-de-donnees', {
props: ['donnees'],
template: `
<div style="border: 1px dashed blue; padding: 10px; margin-bottom: 10px;">
<h4>Mon Tableau de Données (simulé)</h4>
<p>Données affichées: {{ donnees.length }} éléments.</p>
<p v-if="triActif">Tri actif par: {{ triActif }}</p>
</div>
`,
data() {
return {
triActif: 'date' // Simule un tri actif
};
},
methods: {
reinitialiserTri() {
// Logique de réinitialisation du tri ici
this.triActif = null;
console.log("Le tri interne du tableau a été réinitialisé.");
}
}
});
export default {
data() {
return {
dataItems: [
{ id: 1, titre: 'Article A' },
{ id: 2, titre: 'Article B' }
]
};
},
methods: {
effacerLeTri() {
// Appel d'une méthode sur l'instance du composant "mon-tableau-de-donnees"
if (this.$refs.listeArticles && typeof this.$refs.listeArticles.reinitialiserTri === 'function') {
this.$refs.listeArticles.reinitialiserTri();
} else {
console.warn("La méthode reinitialiserTri n'est pas disponible ou la ref est introuvable.");
}
}
},
mounted() {
// Exemple d'accès aux données internes du composant après montage
if (this.$refs.listeArticles) {
console.log("État de tri initial du tableau :", this.$refs.listeArticles.triActif);
}
}
};
</script>
Exemple 3 : Contrôle de la validation d'un formulaire
De nombreux frameworks de formulaire ou bibliothèques de validation utilisent ref pour permettre le contrôle programmatique des champs de formulaire, comme la réinitialisation des messages d'erreur.
<template>
<div>
<!-- Imaginons un composant de champ de formulaire personnalisé "mon-champ-form" -->
<!-- Il expose une méthode "effacerValidations" -->
<mon-champ-form ref="champFichier" :label="'Document PDF'" :regles="reglesUpload">
<input type="file" @change="handleFileChange">
<p v-if="nomFichier">Fichier sélectionné: {{ nomFichier }}</p>
</mon-champ-form>
<button @click="simulerSoumission">Soumettre</button>
<button @click="reinitialiserValidationFichier">Effacer validation du fichier</button>
</div>
</template>
<script>
// Définition d'un composant mock pour 'mon-champ-form'
Vue.component('mon-champ-form', {
props: ['label', 'regles'],
template: `
<div style="border: 1px dashed green; padding: 10px; margin-bottom: 10px;">
<label>{{ label }}:</label>
<slot></slot>
<p v-if="messageErreur" style="color: red;">{{ messageErreur }}</p>
</div>
`,
data() {
return {
messageErreur: null
};
},
methods: {
valider(value) {
// Logique de validation simulée basée sur les 'regles'
if (this.regles && this.regles.includes('required') && !value) {
this.messageErreur = 'Ce champ est requis.';
return false;
}
this.messageErreur = null;
return true;
},
effacerValidations() {
this.messageErreur = null;
console.log(`Validations effacées pour le champ: ${this.label}`);
}
}
});
export default {
data() {
return {
nomFichier: null,
fichierSelectionne: null,
reglesUpload: ['required']
};
},
methods: {
handleFileChange(event) {
const file = event.target.files[0];
if (file) {
this.nomFichier = file.name;
this.fichierSelectionne = file;
// Valide le champ après sélection
this.$refs.champFichier.valider(file);
} else {
this.nomFichier = null;
this.fichierSelectionne = null;
}
},
simulerSoumission() {
// Valider tous les champs ici, ou appeler des méthodes de validation sur d'autres refs
const estValide = this.$refs.champFichier.valider(this.fichierSelectionne);
if (estValide) {
alert('Formulaire soumis avec succès (simulé) !');
} else {
alert('Veuillez corriger les erreurs du formulaire.');
}
},
reinitialiserValidationFichier() {
// Efface spécifiquement la validation du champ "champFichier"
if (this.$refs.champFichier && typeof this.$refs.champFichier.effacerValidations === 'function') {
this.$refs.champFichier.effacerValidations();
}
}
}
};
</script>
En résumé, l'utilisation de l'attribut ref fournit un pont essentiel pour interagir directement avec des éléments DOM ou des instances de composants dans un cadre Vue.js, évitant ainsi la nécessité de manipulations DOM impératives via document.querySelector tout en restant dans l'écosystème Vue.