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

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" ;)

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 ?

C'est cela même. Je te laisse faire, tu me montres quand tu as fini.

{"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=""

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 ?

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 ?

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":""}

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":""}

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