Commentaires
Pour mener à bien notre mini projet, il faut pouvoir réagir aux évènements. Par évènements, j'entends évidemment les actions de l'utilisateur, par exemple le clic, le survol, le clic sur une touche...

Comme en JS Vanille, pour réagir aux évènements avec Vue tu dois d'abord les écouter puis utiliser un callback. Et pour ça, rien de tel qu'une directive. J'ai nommé : v-on

La directive v-on



Arthur, l'apprenti développeurCette directive s'utilise comme toutes celles qu'on a vues précédemment ?
Tout à fait. C'est un attribut qu'on met sur une balise. On précise ensuite l'évènement qu'on écoute (click, change, keyup...) et le callback en paramètre. Voici un exemple très simple :

{"language":"text/html","content":"<main id=\"app\" class=\"px-4 pt-8 w-full flex flex-wrap\">\n <button v-on:click=\"open = !open\">Afficher le contenu</button>\n <div v-show=\"open\">Je suis le contenu à afficher</div>\n</main>\n<script type=\"module\">\n import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'\n createApp({\n data() {\n return {\n open: false,\n }\n }\n }).mount('#app')\n</script>","filename":"index.html"}

Comme pour v-bind, il y a une syntaxe raccourcie. Au lieu d'écrire v-on:EVENT="callback", on peut écrire @EVENT="callback". Par exemple : @click="open = !open" ;)

Arthur, l'apprenti développeurÇa me parait simple !
En effet, ça l'est. On va donc appliquer ça à notre mini projet. On va rajouter un bouton sur chaque article pour pouvoir l'ajouter à notre liste de "consulter plus tard". Cela implique évidemment de créer une nouvelle donnée afin de stocker les articles à lire plus tard !
{"language":"text/html","content":"<script type=\"module\">\n import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'\n createApp({\n data() {\n return {\n loading: true,\n posts: [],\n selection: []\n }\n },\n beforeCreate() {\n this.loading = true;\n },\n created() {\n fetch('https://jsonplaceholder.typicode.com/posts')\n .then((response) => response.json())\n .then((json) => { this.posts = json });\n },\n mounted() {\n this.loading = false\n }\n }).mount('#app')\n\n</script>","filename":"index.html"}

Bon maintenant qu'on a fait ça, que faut-il faire ?

Arthur, l'apprenti développeurIl faut qu'on ajoute un bouton sur chaque article pour l'ajouter à notre "selection" ?
C'est cela même. Je te laisse faire, tu me montres quand tu as fini.

Arthur, l'apprenti développeurVoici ce que j'ai fait !
{"language":"text/html","content":"<div v-else class=\"max-w-7xl mx-auto grid gap-4 grid-cols-3\">\n <article v-for=\"post in posts\" class=\"shadow px-4 pb-8 pt-2 rounded relative\" :key=\"post.id\">\n <a :href=\"`http://monsite.com/${post.id}`\" class=\"mt-4 block\">\n <h2 class=\"text-xl font-semibold text-gray-900\">{{ post.title }}</h2>\n <p class=\"mt-3 text-base text-gray-500\">{{ post.body }}</p>\n </a>\n <button @click=\"selection.push(post)\" class=\"text-sm absolute bottom-2\">Ajouter à ma liste</button>\n </article>\n</div>","filename":"index.html"}



Tu as compris, c'est bien ça !
Bon, et maintenant, ce qu'il faudrait faire, c'est afficher la sélection de l'utilisateur. On va boucler sur "selection" pour afficher la sélection. Je te propose quelque chose d'un peu plus évolué, avec une modale pour que tu voies pas mal de nouvelles choses. Le code est un peu plus compliqué, prends bien le temps de le regarder. Il y a des conditions, des moustaches, des boucles et des évènements.

{"language":"text/html","content":"<!DOCTYPE html>\n<html lang=\"fr\">\n\n<head>\n <meta charset=\"utf-8\">\n <title>Mes premiers pas avec Vue 3</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <style>\n [v-cloak] {\n display: none;\n }\n </style>\n</head>\n\n<body>\n <main id=\"app\" v-cloak>\n <div v-show=\"modal == 'open'\"\n class=\"w-1/2 h-1/2 bg-white px-2 py-2 z-10 overflow-y-auto shadow-md rounded fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2\">\n <h2 class=\"text-xl py-4\">Mes articles en attente</h2>\n <a :href=\"`http://monsite.com/${post.id}`\" v-for=\"post in selection\" :key=\"post.id\" class=\"block\">{{\n post.title\n }}</a>\n </div>\n <div v-if=\"loading\">Chargement en cours...</div>\n\n <p v-if=\"posts.length < 1\"\n class=\"max-w-7xl mx-auto border-l-4 border-yellow-400 bg-yellow-50 p-4 text-sm text-yellow-700\">\n Aucun article à afficher.\n </p>\n <div v-else class=\"max-w-7xl mx-auto grid gap-4 grid-cols-3\">\n <article v-for=\"post in posts\" class=\"shadow px-4 pb-8 pt-2 rounded relative\" :key=\"post.id\">\n <a :href=\"`http://monsite.com/${post.id}`\" class=\"mt-4 block\">\n <h2 class=\"text-xl font-semibold text-gray-900\">{{ post.title }}</h2>\n <p class=\"mt-3 text-base text-gray-500\">{{ post.body }}</p>\n </a>\n <button @click=\"selection.push(post)\" class=\"text-sm absolute bottom-2\">Ajouter à ma liste</button>\n </article>\n </div>\n <footer v-if=\"selection.length > 0\" class=\"fixed bottom-0 right-2 px-2 py-4 rounded bg-gray-300\">\n <button @click=\"modal='open'\">Voir {{ selection.length > 1 ? 'les' : '' }} {{ selection.length }}\n article{{selection.length > 1 ? 's' : '' }} à lire plus tard</button>\n </footer>\n </main>\n\n <script type=\"module\">\n import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'\n createApp({\n data() {\n return {\n loading: true,\n posts: [],\n selection: [],\n modal: 'close',\n }\n },\n beforeCreate() {\n this.loading = true;\n },\n created() {\n fetch('https://jsonplaceholder.typicode.com/posts')\n .then((response) => response.json())\n .then((json) => { this.posts = json });\n },\n mounted() {\n this.loading = false\n }\n }).mount('#app')\n\n </script>\n</body>\n\n</html>","filename":"index.html"}

Les modificateurs



En JS Vanille, il est commun de vouloir utiliser des méthodes de l'interface Event comme stopPropagation ou encore preventDefault. On peut évidemment les utiliser avec Vue.JS, et ce directement dans le HTML avec v-on. C'est ce qu'on appelle les modificateurs.
Pour appliquer preventDefault par exemple, il nous suffit d'écrire :
{"language":"text/html","content":"<button @click.prevent=\"callback...\">Un bouton sur lequel on écoute le clic et où on applique un preventDefault</button>","filename":""}

Pour stopPropagation, ce serait @click.stop=""

Arthur, l'apprenti développeurPratique !
Tout à fait.

Bon Arthur, si tu fais le bilan de ce qu'on a fait jusqu'à maintenant, n'y a-t-il pas quelque chose qui te dérange ?

Arthur, l'apprenti développeurHum... En fait, on peut ajouter un post à notre sélection, mais on ne peut pas en enlever. Et puis, c'est étrange d'utiliser le callback directement dans "le HTML", avant en JS j'utilisais dans mon script un eventListener et une fonction...
En effet, la syntaxe peut être déroutante. Mais elle est super pratique !
Pour ce qui est d'enlever un article de notre sélection, c'est tout à fait juste. Aurais-tu une idée de comment faire ?

Arthur, l'apprenti développeurIl faudrait rajouter une sorte de condition dans nôtre @click sur le bouton pour dire "Si le post est déjà dans la sélection et que je clique à nouveau, alors je l'enlève, sinon je l'ajoute". Mais alors là, avec la syntaxe de Vue, je ne vois pas comment faire...
Tu as raison au niveau de l'algorithme. Et tu as raison, tu ne peux pas le réaliser seulement avec la syntaxe que tu connais. On va devoir appeler une fonction dans notre v-on plutôt qu'une expression directement.
Pour cela, c'est simple, on précise simplement la fonction à appeler en paramètre de v-on !
{"language":"text/html","content":"<button @click=\"maFonction\">Au clic, la fonction \"maFonction\" va être appelée</button>","filename":""}


Arthur, l'apprenti développeurChouette, et si j'ai besoin de passer des paramètres ?
C'est comme si tu étais en JS classique.
{"language":"text/html","content":"<button @click=\"maFonction(parametre1, parametre2, 'du texte', 1, true)\">Au clic, la fonction \"maFonction\" va être appelée avec 5 paramètres</button>","filename":""}


Arthur, l'apprenti développeurMais attends, cette fonction, je la mets où ?
J'attendais ta question avec impatience... En fait, il faut renseigner cette fonction comme une méthode de notre root component. Et c'est justement ce dont on va parler dans la chapitre prochain. On sera alors capable de retirer un article de notre sélection dans le cadre de notre projet. Ready ? J'ai terminé cette partie
Demander de l'assistance