Skip to content

Tout pour WordPress, le développement web — et plus encore

⚡ Apprendre les bases de Vue 3 : d'un dossier vide aux composants

⚡ Apprendre les bases de Vue 3 : d'un dossier vide aux composants

Vous observez Vue 3 et vous voyez un framework frontend élégant parmi les trois grands. React, Angular, Vue: cela semble sérieux. Puis vous ouvrez le premier tutoriel, et vous tombez sur vite, create-vue et des fichiers .vue avec des transpileurs… Alors que vous pouvez en réalité inclure Vue avec une simple ligne <script> et commencer à coder immédiatement. Pas de bundlers, pas de JSX, pas d’enfer de configuration.

L’écart entre «je veux essayer» et «j’ai écrit un composant» est plus court ici que partout ailleurs. Mais la plupart des tutoriels ne comblent pas cet écart; ils ressassent la documentation par fragments sans vous donner une vue d’ensemble. Vous voyez des bouts de syntaxe éparpillés et vous n’arrivez pas à comprendre comment ils se transforment en application.

Ce guide est le chemin exact que nous avons nous-mêmes suivi avec Vue: d’un dossier vide jusqu’aux composants avec des props. Vous écrirez et exécuterez chaque ligne vous-même. Pas de magie, juste du code qui fonctionne et une compréhension de la réactivité, le principal superpouvoir de Vue.

💡 Aperçu rapide:

  • Construire une application Vue depuis un CDN et la monter dans le DOM: votre première instance fonctionnelle en 5 minutes
  • Parcourir quatre directives clés, v-for, v-if, v-on et v-bind: les piliers de tout template Vue
  • Décortiquer les propriétés calculées et les méthodes: quand mettre en cache et quand appeler
  • Extraire la logique dans des composants et transmettre des données via les props: un pas vers une véritable architecture

Créer une application Vue

Commençons à partir de zéro absolu. Pas de create-vue, vite ou vue-cli, juste un dossier avec deux fichiers.

Créez le répertoire et les fichiers dans votre terminal:

1mkdir vue3-intro
2cd vue3-intro
3touch index.html app.js

Ou faites la même chose via votre gestionnaire de fichiers. Ouvrez maintenant index.html et écrivez le squelette:

1<!DOCTYPE html>
2<html lang="ru">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
7 <title>Vue 3 — first steps</title>
8</head>
9<body>
10 <div id="app"></div>
11 <script src="./app.js"></script>
12</body>
13</html>

Trois lignes clés. <script src="https://unpkg.com/vue@3/dist/vue.global.js"> charge Vue 3 depuis un CDN. C’est le moyen le plus rapide de démarrer: la bibliothèque se charge comme un fichier JavaScript classique, sans étape de build. <div id="app"> définit le point de montage: l’endroit dans le DOM où Vue va «vivre». La troisième ligne importe app.js, où nous allons définir la logique.

Remplissons maintenant app.js:

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3'
5 }
6 }
7})
8
9app.mount('#app')

La méthode Vue.createApp() crée une instance d’application. Elle reçoit un objet d’options; ici nous avons déclaré une propriété course via la fonction data(). Vue rend réactive chaque propriété retournée par data(): lorsqu’une valeur change, le DOM se met à jour automatiquement. Aucune manipulation manuelle de l’arbre n’est nécessaire.

Mais l’application doit être «attachée» à un élément de la page. C’est ce que fait app.mount('#app'). Sans cette ligne, Vue ne réagira à aucun changement: l’instance est créée mais pas démarrée.

Il ne reste plus qu’à afficher la propriété dans le HTML. À l’intérieur de <div id="app">, écrivez:

1<h1>{{ course }}</h1>

Les doubles accolades {{ }} sont l’interpolation, le principal moyen d’afficher des données dans les templates Vue. Tout ce qui se trouve à l’intérieur de {{ }} est remplacé par Vue par la valeur de la propriété correspondante issue de data().

Première application Vue 3 dans le navigateur

Ouvrez index.html dans votre navigateur. La page affiche le texte. Votre première application est prête, et vous l’avez écrite vous-même plutôt que de la générer via un CLI.

Afficher des listes

Dans une application réelle, vous travaillez presque toujours avec des tableaux: produits, tags, articles. Vue fournit la directive v-for pour cela.

Ajoutons un tableau de tags à data():

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 tags: ['Vue', 'Frontend', 'JavaScript']
8 }
9 }
10})

Et dans le HTML, une liste:

1<ul>
2 <li v-for="tag in tags">{{ tag }}</li>
3</ul>

La directive v-for itère sur le tableau tags et crée son propre <li> pour chaque élément. La variable tag à l’intérieur de la boucle est l’élément courant. Le résultat ressemble à ceci:

Liste de tags Vue 3 avec la directive v-for

Une nuance importante: lors de l’itération sur un tableau, chaque élément du DOM a besoin d’une clé unique. Vue l’utilise pour suivre l’identité des nœuds lors des mises à jour, ce qui accélère le re-rendu et évite les bogues liés à l’état.

1<ul>
2 <li v-for="(tag, index) in tags" :key="index">{{ tag }}</li>
3</ul>

:key est un raccourci pour v-bind:key, qui lie l’attribut key à la valeur de l’index. Si vous avez un tableau d’objets, par exemple { id: 1, name: 'Vue' }, utilisez id comme clé plutôt que l’index. L’index change lors d’un réordonnancement, tandis que id est stable, ce qui le rend plus fiable.

Affichage conditionnel

Vous avez souvent besoin d’afficher ou de masquer un élément selon une condition: un bouton d’achat uniquement si la formation est disponible. Vue gère cela avec la directive v-if.

Ajoutons un indicateur available dans data():

1data() {
2 return {
3 course: 'Introduction to Vue 3',
4 description: 'Basic guide to Vue 3 for beginners',
5 price: '$19.99',
6 available: true,
7 tags: [
8 { id: 1, name: 'Vue' },
9 { id: 2, name: 'Frontend' },
10 { id: 3, name: 'JavaScript' }
11 ]
12 }
13}

Et utilisons-le dans le balisage:

1<p v-if="available">Course available for purchase!</p>
2<p v-else>Unfortunately, the course is currently unavailable.</p>

v-if évalue l’expression entre guillemets. Si elle est vraie, le premier bloc s’affiche; sinon, v-else prend le relais. Essayez d’exécuter app.available = false dans la console du navigateur et observez la réaction instantanée de la page.

Rendu conditionnel dans Vue 3 avec v-if

En plus de v-if / v-else, il existe aussi v-else-if pour les chaînes de conditions, ainsi que v-show. La différence est fondamentale: v-if retire complètement l’élément du DOM, tandis que v-show se contente de basculer display: none. Privilégiez v-if quand la condition change rarement. Utilisez v-show pour les basculements fréquents, comme des onglets, lorsque la performance est importante.

Gestion des événements

La directive v-on, ou @ en abrégé, écoute les événements du DOM: clics, saisie, survol. Lorsqu’un événement se déclenche, Vue exécute la méthode ou l’expression indiquée.

Ajoutons une méthode purchase aux options de l’application:

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 available: true,
8 tags: [
9 { id: 1, name: 'Vue' },
10 { id: 2, name: 'Frontend' },
11 { id: 3, name: 'JavaScript' }
12 ]
13 }
14 },
15 methods: {
16 purchase() {
17 console.log('Course purchased!')
18 }
19 }
20})

La section methods contient des fonctions accessibles dans le template et dans les autres méthodes via this. Relions maintenant l’appel à un bouton:

1<button @click="purchase">Buy</button>
Gestion d'un clic dans Vue 3 avec v-on

Pour des actions simples, vous pouvez écrire le code directement dans @click:

1<button @click="available = !available">Toggle availability</button>
Basculer l'état d'un bouton dans Vue 3

Le code inline de ce type est pratique pour des opérations courtes comme basculer un indicateur. En revanche, déplacez toujours la logique complexe dans des méthodes; le template doit rester lisible. Une règle simple: counter += 1 est acceptable dans le template, mais dix lignes de logique d'achat ont leur place dans une méthode.

Lier les attributs

Les attributs comme src, href ou alt doivent souvent être dynamiques. La directive v-bind, ou : en raccourci, lie la valeur d'un attribut à une expression Vue.

Ajoutons des données pour une image:

1data() {
2 return {
3 // ...other properties
4 imgURL: 'https://catalins.tech/img',
5 imgDescription: 'Photo of a desk with a computer'
6 }
7}

Dans le template, lions-les à un élément <img>:

1<img :src="imgURL" :alt="imgDescription" width="500" height="350">

La forme complète serait v-bind:src="imgURL"; les deux-points ne sont qu'un sucre syntaxique. Vue suit désormais imgURL et imgDescription: modifiez-les dans data(), et l'image sur la page se met à jour automatiquement. C'est la réactivité en action.

Lier les attributs d'image avec v-bind

Le même principe s'applique aux attributs comme :href, :disabled et :class, ainsi qu'à tous les autres. Essayez par vous-même: ajoutez un lien avec un href dynamique provenant de data() et vérifiez qu'il fonctionne sans une seule ligne supplémentaire.

Propriétés calculées

Il arrive que des données doivent être transformées avant affichage: formater un prix, concaténer un prénom et un nom, vérifier une condition. Vue fournit les propriétés computed pour cela.

Imaginez que vous souhaitiez toujours avoir une description d'image, même si le champ imgDescription est vide. Écrivons une propriété calculée:

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 available: true,
8 imgURL: 'https://catalins.tech/img',
9 imgDescription: 'Photo of a desk with a computer',
10 tags: [
11 { id: 1, name: 'Vue' },
12 { id: 2, name: 'Frontend' },
13 { id: 3, name: 'JavaScript' }
14 ]
15 }
16 },
17 computed: {
18 hasImageDescription() {
19 return this.imgDescription.length > 0
20 ? this.imgDescription
21 : 'Automatic image description'
22 }
23 }
24})

Utilisez maintenant la propriété calculée dans le template au lieu de la donnée brute:

1<img :src="imgURL" :alt="hasImageDescription" width="500" height="350">

Vue met en cache le résultat d'une propriété computed et ne le recalcule que lorsque ses dépendances changent, dans notre cas imgDescription. C'est plus efficace que d'appeler une fonction à chaque rendu.

Une règle importante: les propriétés calculées sont destinées à afficher des données, pas à les modifier. Ne modifiez pas l'état de l'application à l'intérieur d'une computed; utilisez des méthodes pour cela.

Méthodes vs propriétés calculées

La différence entre methods et computed se résume à une question: êtes-vous en train de modifier des données ou d'afficher une valeur dérivée?

Les propriétés calculées relèvent de la couche de présentation. Formatage, filtrage, vérifications de conditions, concaténation de chaînes. Elles sont mises en cache et n'ont pas d'effets de bord.

Les méthodes servent aux actions. Modifier une valeur dans data(), envoyer une requête, basculer un indicateur. Elles sont appelées explicitement et peuvent tout faire.

Un anti-pattern typique consiste à modifier this.course à l'intérieur d'une propriété computed. Une propriété calculée réagit aux changements de course mais ne doit pas la modifier elle-même. Utilisez toujours une méthode pour modifier des données. Laissez le template décrire «quoi afficher», et non «comment le calculer».

Composants et props

Lorsqu'une application grandit, tout conserver dans un seul fichier devient ingérable. Vue vous permet de découper l'interface en composants: des blocs isolés avec leur propre logique, template et styles.

Créons notre premier composant, CourseCard:

1mkdir components
2touch components/CourseCard.js

Dans components/CourseCard.js, définissez le composant:

1app.component('coursedisplay', {
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 available: true,
8 imgURL: 'https://catalins.tech/img',
9 imgDescription: 'Photo of a desk with a computer',
10 tags: [
11 { id: 1, name: 'Vue' },
12 { id: 2, name: 'Frontend' },
13 { id: 3, name: 'JavaScript' }
14 ]
15 }
16 },
17 computed: {
18 hasImageDescription() {
19 return this.imgDescription.length > 0
20 ? this.imgDescription
21 : 'Automatic image description'
22 }
23 },
24 template: `
25 <img :src="imgURL" :alt="hasImageDescription" width="500" height="350">
26 <h1>{{ course }}</h1>
27 <p>{{ description }}</p>
28 <p>{{ price }}</p>
29 <button @click="available = !available">Buy</button>
30 <ul>
31 <li v-for="tag in tags" :key="tag.id">{{ tag.name }}</li>
32 </ul>
33 <p v-if="available">Course available for purchase!</p>
34 <p v-else>Unfortunately, the course is currently unavailable.</p>
35 `
36})

Le premier argument de app.component() est le nom que nous utiliserons en HTML comme balise: <coursedisplay></coursedisplay>. Le second est un objet avec data(), computed et template, les «internes» du composant.

Incluons maintenant le composant dans index.html et utilisons-le:

1<div id="app">
2 <coursedisplay></coursedisplay>
3</div>
4<script src="./app.js"></script>
5<script src="./components/CourseCard.js"></script>
6<script>
7 const mountedApp = app.mount('#app')
8</script>

Nous avons importé le fichier du composant, nous l'avons utilisé comme balise personnalisée et nous avons monté l'application directement dans le HTML. La logique du cours est désormais encapsulée dans CourseCard, tandis que app.js est seulement responsable de créer l'instance.

Props: transmettre des données entre composants

Les props (abréviation de properties) sont le mécanisme pour transmettre des données d'un composant parent à un enfant. Le composant enfant déclare les props qu'il accepte, et le parent les passe sous forme d'attributs.

Ajoutons une prop paid à CourseCard qui indique si le cours est payant ou gratuit:

1app.component('coursedisplay', {
2 props: {
3 paid: {
4 type: Boolean
5 }
6 },
7 // ...rest of the configuration
8})

Le parent, dans notre cas app.js, transmet la valeur:

1const app = Vue.createApp({
2 data() {
3 return {
4 allCourses: 1,
5 paid: true
6 }
7 }
8})

Et dans index.html, nous passons la prop:

1<coursedisplay :paid="paid"></coursedisplay>

Vue valide automatiquement le type de la valeur transmise. Si un Boolean est attendu mais qu'une chaîne est reçue, le framework émettra un avertissement dans la console. Cela vous évite des erreurs bêtes à mesure que la base de code grandit.

Pour rendre une prop obligatoire, ajoutez required: true à sa définition. Vue se plaindra alors si le parent ne transmet pas de valeur, vous permettant ainsi de découvrir le problème avant qu'il ne casse l'interface.

Vous trouverez le code complet de ce guide dans le dépôt vue3-intro sur GitHub, qui contient les fichiers finis index.html, app.js et components/CourseCard.js. Forkez-le et expérimentez.

Vidéo associée

Pour renforcer la matière par la pratique, regardez la première leçon du cours Vue 3 de Net Ninja; elle complète bien ce guide avec une démonstration de code en direct:

⁉️🤔 Foire aux questions

Puis-je utiliser Vue 3 sans bundler en production?

Oui, l'inclure via CDN (unpkg.com/vue@3/dist/vue.global.js) fonctionne aussi en production. Mais pour de vrais projets, nous recommandons de passer à Vite: vous bénéficiez du tree-shaking, du code-splitting et des composants monofichiers, ce qui simplifie considérablement le développement à mesure que l'application grandit. Le template de démarrage npm create vue@latest met tout cela en place en une minute.

Quelle est la différence entre v-if et v-show?

v-if supprime complètement l'élément du DOM lorsque la condition est fausse. v-show conserve l'élément dans le DOM mais bascule la propriété CSS display: none. Utilisez v-if quand la condition change rarement, par exemple pour un rôle utilisateur. Utilisez v-show pour des basculements fréquents comme des onglets, où la vitesse de rendu importe et où vous voulez éviter de recréer des nœuds.

La clé:key est-elle obligatoire dans v-for?

Techniquement, v-for fonctionne sans :key, mais Vue émettra un avertissement dans la console. Sans clé, le framework ne peut pas suivre quel élément du DOM correspond à quel élément de donnée, ce qui entraîne des bugs lors du réordonnancement et de la suppression. Spécifiez toujours :key avec un identifiant unique, l'id de vos données plutôt que l'index du tableau.

Quelle est la différence entre data() et computed?

data() stocke l'état original, les données «brutes». computed en dérive une valeur pour l'affichage: une chaîne formatée, un tableau filtré, un résultat de validation. Une propriété calculée se met à jour automatiquement lorsque ses dépendances changent et est mise en cache entre les rendus. Les méthodes, en revanche, sont appelées à nouveau à chaque fois et sont destinées aux actions, pas à l'affichage.

Peut-on mélanger Options API et Composition API?

Oui, vous pouvez utiliser les deux styles dans un même projet. Vue 3 prend entièrement en charge l'Options API, tandis que la Composition API est un outil supplémentaire pour les scénarios complexes. Pour l'apprentissage, nous recommandons de commencer par l'Options API: elle est plus structurée et plus proche du modèle mental «un composant est un objet avec des options».

Que faire ensuite: votre prochaine étape avec Vue 3

Vous avez construit votre première application, exploré les directives, les propriétés calculées et les composants. C'est la fondation sur laquelle tout projet se construit, d'une page d'atterrissage à un panneau d'administration.

Trois voies s'offrent à vous. Premièrement, consolidez par la pratique: prenez une API publique comme JSONPlaceholder et affichez une liste d'articles avec filtrage via computed. Deuxièmement, passez à Vite et aux fichiers .vue: la documentation officielle de Vue 3 vous guidera de create-vue à votre premier SFC en une heure. Troisièmement, apprenez Vue Router et Pinia pour construire une SPA complète.

Si vous souhaitez essayer Vue sans aucune installation, consultez l’article sur l’intégration de Vue via CDN. Le code de démarrage de ce guide se trouve dans le dépôt vue3-intro ; n’hésitez pas à le forker et à expérimenter.