Aide mémoire: S4 - R4.A.10 - JavaScript

Sujet 2

Sujet 3

Sujet 4

Sujet 5

Sujet 6

Sujet 7

Sujet 8

Sujet 2

Boucle d'événements

On voit donc que le code JS s’exécute très vite, en quelques millisecondes.
L'utilisateur ne s’aperçoit pas de ce blocage très court.
A la fin de notre code JS (fin du <script>), on rend la main au navigateur.

Que fait le navigateur ensuite ?
Le navigateur passe la plupart de son temps dans la « boucle d'événements »... à ne rien faire.
De temps en temps (au plus toutes les 16 millisecondes), il se rend compte que quelque-chose à changé (par exemple, le chat animé a bougé) et qu'il est temps de mettre à jour l'affichage.
Alors, il met à jour l'affichage.

Boucle d'événements

Execution JS

xyz

Affichage

Boucle d'événements et JS

Lorsqu'on appuie sur le bouton, le navigateur ajoute une tache JS à exécuter dans la liste (à gauche de l'animation ci-dessous).
Lorsque ce code JS a fini de s'exécuter il rend la main au navigateur, qui retourne dans la boucle d'événements.
Plus tard, il rafraîchit l'affichage si nécessaire (l'image du chat bouge).

Boucle d'événements

Execution JS

xyz

Affichage

JS bloquant

Lorsque le JS bloque, le navigateur reste coincé et ne retourne pas à la boucle d'événements.

Remettons la boucle infinie:

              while(true);

Boucle d'événements

Execution JS

xyz

Affichage

JS et Affichage

Essayons de comprendre le déplacement de l'image de la souris.

Boucle d'événements

Execution JS

xyz

Affichage

setTimeout explications

Explications:

console.log('début');
setTimeout(()=>{
       console.log('bonjour');
    }, 5000);
console.log('fin')

Boucle d'événements

Execution JS

xyz

Affichage

Exécution différée: faire une action plus tard

Le code suivant

setTimeout(xyz, 1234)  

permet de dire au navigateur « Tiens, prends cette fonction xyz et enregistre-là pour l'exécuter plus tard » (dans 1234 ms).
On a fourni au navigateur une action qu'il doit faire plus tard.

Le code suivant

document.addEventListener('click',xyz);

permet de dire au navigateur « Tiens, prends cette fonction xyz et exécute-là plus tard » (quand l'utilisateur clique)
On a fourni au navigateur une action qu'il doit faire plus tard.

En JS, on cherche souvent à faire exécuter des actions plus tard. Ces actions sont des fonctions.
C'est pour ça qu'on a autant besoin de manipuler des fonctions. Les fonctions anonymes sont une manière pratique (mais pas indispensable) de le faire.
Une fonction qu'on fournit pour être appelée plus tard s’appelle un « callback »

Callback Hell

Pour enchaîner dans le temps des opérations, on a dû emboîter des fonctions. Ce n'est pas très lisible.
Ici, on n'en a emboîté que 3, mais en pratique, ça peut être bien pire.

Cette situation arrive souvent en JS quand on veut enchaîner des opérations qui sont décalées dans le temps.
Cette situation a un nom: « Callback Hell ».

Pour résoudre ce problème et faciliter la vie des développeurs, le JS propose deux outils, liés:


Promesses

En JS, une promesse (Promise) est un objet qui représente une opération future.
Il sert à faciliter l’exécution différée.
Dans ce cours, on va apprendre à utiliser des  promesses, mais pas à en créer nous mêmes (c'est moins courant).

Commençons par un exemple.

Utilisation promesse

			const p=range_ta_chambre('Tom');
console.log(p);
« p » est une promesse.
La fonction range_ta_chambre ne range pas la chambre toute de suite.
Dans l'immédiat, elle nous donne juste une promesse: de ranger sa chambre, plus tard.
On sait bien que ce type de promesse pourra être tenue ... ou pas.

En JS, une promesse peut avoir trois états:
Ranger sa chambre peut prendre du temps ...
Au début, « p » est « en attente ». Après quelques secondes elle deviendra « tenue » ou « rompue ».
On ne manipule pas ces états directement... mais c'est très important de comprendre qu'ils existent.

then

Comme on l'a vu, on ne peut pas bloquer le JS en attendant que cette promesse aboutisse.
On va donc fournir à la promesse une fonction (callback) qu'elle pourra appeler plus tard.
Pour ça, l'objet « p » a une méthode appelée « then ».
« then » prend en paramètre une fonction qui sera appelée si la promesse est tenue.

Que faut-il écrire pour afficher « Trés bien! » dans la console quand la promesse « p » est tenue ?

(Essayez dans votre <script> ou dans la console avant de répondre)
(utilisez une fonction fléchée, sans paramètre, et avec des accolades {...} )

Catch

Comment faire pour réagir si la promesse n'est pas tenue  (elle est rompue) ?

Comme la méthode then(...), les promesses ont une méthode catch(...), qui prend une fonction en paramètre:

            const p=range_ta_chambre('Tom');
            p.catch(()=>{console.log('Tu es vilain!');});
Essayez dans votre navigateur.

Enchaîner then() et catch()

La méthode p.then(...) renvoie une nouvelle promesse.

On pourrait la mettre dans une nouvelle variable « p2 », comme ceci:

let p=range_ta_chambre('Tom');
let p2=p.then(()=>{console.log('Trés bien!');});

Mais, le plus souvent, on l'utilisera directement, pour enchaîner avec catch:

p.then(()=>{console.log('Trés bien!');}).catch(()=>{console.log('Tu es vilain!');});

La même chose en 2 lignes:

p.then( ()=>{console.log('Trés bien!');})
.catch(()=>{console.log('Tu es vilain!');});

Très souvent, on ne met pas non plus la première promesse (p) dans une variable. Ce qui donne:

range_ta_chambre('Tom')
.then( ()=>{console.log('Trés bien!');})
.catch(()=>{console.log('Tu es vilain!');});
Essayez le code précédent. Vous ne devriez plus avoir de message d’erreur.

Le « Callback hell » du rangement

			range_ta_chambre('Tom',1).then(()=>{
range_ta_chambre('Paul',1).then(()=>{
range_ta_chambre('Jean',1);
})
});

On se retrouve dans la situation du chat poursuivant la souris: des fonctions, dans des fonctions, dans des fonctions...

Solution

Si la fonction (ici anonyme) fournie à .then() retourne une promesse, alors on peut enchaîner les appels à .then() :

			range_ta_chambre('Tom',1)
.then(()=>{return range_ta_chambre('Paul',1);})
.then(()=>{return range_ta_chambre('Jean',1);})

C'est plus propre.

async / await

Les promesses aident à simplifier le code, mais restent lourdes à utiliser.
Ceci étant, elles permettent (parfois) l'utilisation de « await »... qui simplifie énormément le code 😀

« await » permet de faire comme si on attendait, sans réellement bloquer le JS, donc en rendant la main au navigateur.

console.log('bonjour');
await attendre(5000);
console.log("ceci s'affiche vraiment 5s après !!! :-)");

Explication:


async

await est vraiment très pratique...  et a un coté un peu « magique »

await fait des choses « bizarres ». Il arrête l’exécution en plein milieu d'une fonction, pour la reprendre, plus tard, au même endroit.
Pour que ça puisse marcher, la fonction qui contient await doit être un peu particulière. Elle doit être déclaré comme « async »:

async function exemple() {
console.log('bonjour'); await attendre(5000); console.log("ceci s'affiche vraiment 5s après !!! :-)");
}
Petit détail:
Vous ne pouvez pas utiliser await directement dans un script normal (sauf si vous mettez await dans une fonction async):
<script>    
    await attendre(5); // erreur !
</script>
Il faut ajouter type="module"
<script type="module">    
    await attendre(5); // ok
</script>
ATTENTION: 2023:
<script type="module"> Ne fonctionne pas dans les anciennes versions (<89) de Firefox  installées dans certaines salles de l'IUT. Vous devez ajouter une fonction "async" autour du code qui utilise "await" et appeler la fonction.
Exemple:
<script>
     (async function(){
           // votre code
           await exemple();
     })();
</script>

await

Voyons le déroulement de « await »:

Boucle d'événements

Execution JS

xyz

Affichage

Sujet 3

Requêtes AJAX

Toutes le requêtes qu'on a vu, sont faites au chargement de la page.
Le navigateur reçoit le HTML initial et le traite. Quand il y trouve des ressources externes (images, JS, CSS, ...); il les télécharge.
Dans le premier exemple, quand le navigateur voit ceci:

		<img id="chat" src="chat.png" alt="chat"/>

il déclenche le téléchargement de https://moodle.iutv.univ-paris13.fr/img/bjs2/chat.png

AJAX: à partir du JS

Les interactions avec le serveur sont aussi possibles après le chargement de la page:

Voyons quelques exemples.

Ajax: exemple recherche Google



Quand un utilisateur commence à taper une recherche dans Google, Google lui propose une liste de suggestions.

Il est impossible d'inclure dans la page d'origine toutes les suggestions possibles. Le navigateur va donc demander au serveur la liste de suggestions au fur et à mesure que l'utilisateur écrit. Ceci se fait sans recharger la page.

Dans ce qu'on a vu jusqu'à maintenant, les interactions avec le serveur se faisaient au moment du chargement de la page.

Ici, la liste des suggestions est cherchée à partir du serveur, à partir du JS et après la fin du chargement de la page.

Ajax: commentaires

Dans cet exemple, l'utilisateur appuie sur un bouton « J'aime » dans les commentaires d'une vidéo sur Youtube. Son action est enregistrée sur le serveur, mais la page ne se recharge pas.

Le fonctionnement habituel en HTML du bouton consiste à envoyer une requête POST et afficher une nouvelle page. Le rechargement de la page est désagréable pour l'utilisateur. C'est lent, la vidéo s'interrompt, il perd sa position dans la page...

Ici, la requête sur le serveur se fait sans rechargement de la page.

AJAX


AJAX veut dire « Asynchronous JavaScript and XML »

simple_fetch()

En pratique, les requêtes Ajax peuvent se faire de différentes manières:

Le choix ici, est d'utiliser simple_fetch(), une fonction qu'on vous fournit, qui est une version simplifié de fetch. Elle vous aidera à débuter.


Paramètres GET

Paramètres GET

On peut envoyer des informations au serveur, tout simplement en les mettant dans l'URL d'une requête.
On commence les paramètre GET avec un « ? ». Ensuite on met le nom (abc) et sa valeur (def) associée:
http://exemple.org/ma-page.php?abc=def
Si on veut ajouter plusieurs valeurs, on utilise un « & »:
http://exemple.org/ma-page.php?abc=def&rst=uuuuu

Écrivez l'URL suivante en ajoutant un paramètre GET appelé « nom » et ayant comme valeur « Tom »

https://moodle.iutv.univ-paris13.fr/img/bjs2/sujet-3-fetch-1.php

Que vaut une promesse ?

Les promesses ont une valeur (du moins en JS).
Une promesse représente une opération future, qui peut renvoyer une valeur. C'est la « valeur » de la promesse.

Par exemple, lorsqu'on fait une requête AJAX avec simple_fetch, on veut pouvoir récupérer la réponse du serveur.
simple_fetch() renvoie une promesse. La réponse du serveur sera la « valeur » de la promesse. Cette valeur n'est pas disponible au départ. Elle n'est disponible que lorsque la promesse est tenue. On ne peut récupérer la valeur qu'après que la promesse soit tenue, c'est à dire dans la fonction donnée à .then() ou bien après « await ».

Les deux manières de récupérer:

1. En paramètre de la fonction:

simple_fetch('http://exemple.org/abc.php').then( (valeur)=>{console.log(valeur);});

2. Lorsqu'on utilise « await »

let valeur= await simple_fetch('http://exemple.org/abc.php');
console.log(valeur);


Sujet 4

Rappels: Technologies client / serveur

Les interactions client/serveur peuvent devenir complexes. De nombreuses requêtes se font du navigateur au serveur. Les informations et même les logiciels couvrent l'un et l'autre. Pour ne pas se perdre, il est important de bien garder en tête où est employée chaque technologie (client ou serveur ?).
Pour le web, le terme "client" veut dire la même chose que "navigateur".

Dans le développement web on parle aussi de « frontend » pour ce qui se passe dans le navigateur et de « backend » pour ce qui se passe sur le serveur.


API

chat.php est déjà écrit, vous n'aurez pas à le modifier.
C'est une situation classique dans laquelle on se retrouve quand on développe en « frontend »:

On développe du code JS « frontend » sur le navigateur.
On accède à un service « backend » existant déjà sur un serveur. Ce « backend » fournit une API.

L'API consiste ici, des URL suivantes:
http://localhost/~__user_nb__/chat.php?action=messages
http://localhost/~__user_nb__/chat.php?action=nom
http://localhost/~__user_nb__/chat.php?action=changer-nom
http://localhost/~__user_nb__/chat.php?action=envoyer
http://localhost/~__user_nb__/chat.php?action=reinitialiser
http://localhost/~__user_nb__/chat.php?action=test
On a déjà vu « test ». On verra comment utiliser chacune d'entre-elles.

GET / POST

Quand on fait une requête HTTP, on utilise une « méthode ».
La méthode par défaut est « GET ».
Une autre méthode est appelée « POST »

Les requêtes GET et POST peuvent toutes les deux contenir des informations dans l'URL
http://example.com/abc?nom=Tom
La requête POST envoie, en plus, des informations dans le corps de la requête. Ces informations n’apparaissent pas dans l'URL.

Raccourcis nom propriété

En JS on crée beaucoup d'objets et on se retrouve souvent dans la situation suivante:

let nom='Tom';
let o={ nom: nom };

ou bien

let a='Joe', b=123;
let o={a:a,b:b};

Quand la valeur de la propriété est une variable ayant le même nom que la propriété, le JS permet de raccourcir :-)

{a:a,b:b} se racourcit en {a,b}

Comment se raccourcit {nom:nom} ?

Sujet 5

Node.js

Node.js est un environnement permettant d’exécuter du JS en-dehors du navigateur.

Il peut-être utilisé coté serveur, mais il peut aussi être utilisé dans d'autres contextes, comme la plupart des langages de programmation.

Node.js n’étant pas dans le navigateur, on ne peut pas accéder au DOM.
Par contre, on peut accéder aux fonctionnalités du système, qui ne sont pas disponibles dans le navigateur (pour des raisons de sécurité).
On peut lire et écrire des fichiers, on peut créer des serveurs, on peut créer des processus, on peut accéder à une base de données, etc.


Essayons Node.js !

Ouvrez un terminal.

Tapez:
$ node

Vous êtes dans une console, similaire à celle du navigateur!

Essayez des instructions, comme « 1+1 » ou « console.log('Bonjour') »

Modules JS

Pour pouvoir utiliser des fonctionnalités fournies par différentes librairies, il faut d'abord aller les chercher.
Vous l'avez vu dans d'autres langages: « import » dans python et Java, « include » ou « require » en PHP. «include » en C.

Node.js propose deux manières de le faire:

[Dans ce cours (écrit en 2023), on a choisi d'utiliser « import », parce-que c'est l'approche qui parait avoir le plus d'avenir.]

Exemple d'import:
import * as fs from 'node:fs/promises';
Ceci veut dire :
« importer tout le contenu de la librairie « node:fs/promises » dans un objet qu'on veut appeler « fs » »
node:fs/promises : on veut la version « promises » de la librairie fs qui fait partie de Node.js.
fs veut dire « filesystem ». C'est la librairie permettant de manipuler des fichiers.
Certaines librairies, comme fs, existent en plusieurs versions (synchrone, callback, promesses). Dans ce cours, on utilisera les promesses.

Maintenant, on a l'objet « fs », qui contient plein de fonctions. Celle qui nous intéresse est « readFile »:
import * as fs from 'node:fs/promises';

const pass=await fs.readFile('/etc/passwd','utf8');
Remarquez que readFile retourne une promesse. On utilise « await »

Pour pouvoir utiliser import, il faut être dans un « module ». Au lieu d'utiliser des fichiers « .js » (exemple.js) on va utiliser des fichier « .mjs » (exemple.mjs).

Node.js asynchrone

Dans Node.js on va utiliser une approche « asynchrone », comme dans le navigateur.
C'est à dire, qu'on ne doit pas bloquer l’exécution du JS.
Toutes les opérations qui prennent du temps (lire un fichier, faire une requête à une base de données, attendre une connexion réseau...), doivent se faire en deux temps:

Souvent, on peut utiliser des promesses.
Dans ce cas, on peut utiliser async/await pour éviter d'utiliser un callback:

console.log('avant');
const pass=await fs.readFile('/etc/passwd','utf8');
console.log('après');
...

Sans « await », on aurait du écrire:

console.log('avant');
fs.readFile('/etc/passwd','utf8').then(pass=>{
console.log('après');
...
});
(Remarque: il est possible en Node.js de faire du code qui n'est pas asynchrone, en utilisant des versions bloquantes de fonctions comme readFile. Cette approche est moins utilisée et elle est incompatible avec les logiciels qu'on verra ici: Express, Vue.js ...)

NPM : node package manager

Dans l'exemple précédent on a utilisé la librairie 'fs', qui est intégrée à Node.js

En général, on veut aussi utiliser d'autres librairies.
npm est à la fois une commande permettant de gérer des paquets et un répertoire en ligne de paquets qu'on peut installer.
Ce répertoire « npm » fournit plus d'un million de paquets.
Chacun peut y publier ses propres paquets.


La commande « npm »

Généralement, pour utiliser npm, vous devez mettre votre logiciel dans un répertoire à lui.
La commande npm s’utilise alors dans ce répertoire.

Elle utilise un fichier « package.json » qui décrit votre logiciel et ses dépendances.
Les dépendances sont les paquets ("librairies") dont votre logiciel a besoin pour fonctionner.

npm fournit de nombreuses sous-commandes. En voici deux:

npm init permet de créer le fichier package.json

npm install permet d'installer un paquet. Elle va télécharger le paquet à partir du répertoire npm sur le web et va l'écrire dans un sous-répertoire de votre logiciel appelé « node_modules ». npm install va aussi chercher les dépendances du paquet, et les dépendances des dépendances, etc. Tous ces paquets sont mis dans node_modules. node_modules grossit vite et s'est fait une réputation.
npm install va aussi ajouter dans package.json le nom du paquet installé. Ceci permet de savoir quelle est la liste des dépendances de votre logiciel.
Un fichier package-lock.json est aussi mis à jour. Ce fichier est géré automatiquement, vous n'avez pas à vous en préoccuper. Il enregistre les versions précises de chaque paquet utilisé.


Architecture

Express et PHP ont des architectures très différentes.

PHP

Pour utiliser PHP un logiciel appelé « serveur web » est nécessaire (Apache, NGINX). 
Il reçoit les requêtes provenant des navigateurs (http://.../ex1.php, http://.../ex2.php,...)
Il trouve les fichiers PHP correspondants
Il exécute chacune de ces requêtes PHP dans un processus différent

Chaque processus peut durer longtemps (quelques centaines de ms): chaque processus peut s’arrêter en attendant une opération longue (le contenu d'un fichier, le résultat d'une base de données, etc). Le développeur PHP n'a pas besoin de s'occuper de ces attentes. C'est géré automatiquement par le fait qu'il y ait plusieurs processus.

Express.js

Dans Express, il n'y a pas de serveur séparé. Il n'y a qu'un seul processus. Votre programme (app.js) est le serveur.
Les requêtes sont traitées les unes après les autres. Comme le code JS doit être non-bloquant, chaque requête est traitée très rapidement puis rend la main à la boucle d'événements.
S'il y a une opération longue à gérer, le développeur doit utiliser une des techniques de programmation asynchrone (callback, Promise, await).

Pourquoi ?

C'est un problème de performance.
Lancer des processus (ou même réutiliser des processus existants) c'est long.
L'architecture JS est plus rapide. Il n'y a pas de processus à lancer. Le prix à payer est la programmation asynchrone, qui est plus compliquée... même si « await » simplifie beaucoup les choses.


Décortiquons app.js

import express from 'express';
const app = express();
On importe une fonction qu'on choisit d'appeler « express » à partir du paquet « express ».
Ensuite, on appelle cette fonction « express ». Elle nous renvoie un objet qu'on met dans une variable « app ».
Cet objet représente notre application Express.

app.listen(3000, () => {
  console.log('Notre app express écoute sur le port 3000')
});
app.listen crée le serveur, qui écoute sur le port 3000. Normalement, un serveur web (http) est sur le port 80, mais pour utiliser le port 80, on aurait besoin d'être root.
On fournit à app.listen une fonction fléchée, que Express appelle dès que le serveur est prêt. On l'utilise juste pour afficher un message dans le terminal.

app.get('/', (requete, reponse) => {
  console.log('Requete GET / reçue');
  reponse.send('Hello World!')
})
Ici, on dit à Express:
« Quand l'utilisateur demande l'URL http://localhost:3000/  il faut appeler la fonction fléchée fournie »
Ceci s'appelle une « route ».  Remarquez le nom « .get ». Il existe aussi « .post ».

Le chemin '/' est un peu court. Voici un exemple plus clair avec une URL plus longue:
app.get('/bonjour', (requete, reponse) => {
  console.log('Requete GET /bonjour reçue');
  reponse.send('Bonjour à toi!')
})
Ceci dit à Express:
« Quand l'utilisateur demande l'URL http://localhost:3000/bonjour  il faut appeler la fonction fléchée fournie »


Sujet 6

Parcourir un objet en JS

En JS, il y a de nombreuses (beaucoup trop) manières de parcourir un objet.

Prenons un exemple:

let exemple={
"Joe": 123,
"Leila": 543,
"Tom": 91,
};
On voudrait faire une boucle pour parcourir soit les clés ("Joe", "Leila", "Tom" ), soit les valeurs (123,543,91), soit les deux (clés et valeurs).

Les boucles for...in posent des problèmes (hasOwnProperty, Object.hasOwn...).

L'idée est de transformer l'objet en un tableau et utiliser une boucle for...of:

Parcourir les valeurs:

Object.values(...) renvoie un tableau JS (et non pas un objet) avec toutes les valeurs.
On peut alors parcourir ce tableau avec une boucle for...of:

for(const  valeur of Object.values(exemple)){ 
console.log(valeur);
}

Parcourir les clés et les valeurs :

Object.entries(...) renvoie un tableau JS (et non pas un objet) constitué de petits tableaux contenant 2 éléments :une clés et une valeurs:

Object.entries(exemple) renvoie:

[
["Joe", 123],
["Leila", 543],
["Tom", 91],
]

On peut alors parcourir ce tableau avec une boucle for...of:

for(const [cle,valeur] of Object.entries(exemple)){ 
console.log(cle,valeur);
}

Sujet 7

Vue.js : premiers pas

Vue.js est un framework frontend pour construire des pages web ayant beaucoup d'interactions.
Vue.js a des points communs avec React, Angular, Svelte et d'autres.

Ces frameworks sont souvent utilisés pour construire des « single page applications », c'est à dire des sites où l'utilisateur reste sur la même page et toutes les interactions sont gérées par JS et Ajax.


SPA : single page application

Dans l'approche classique, la navigation se fait en cliquant sur des liens ou en appuyant sur des boutons de formulaires. A chaque fois une nouvelle page (P) est visitée. La page visitée peut avoir des interactions JS, mais, en général, elles ne changent pas l'essentiel de l'affichage de la page. De temps en temps une interaction AJAX (A) peut venir enrichir cette navigation.

À l'autre extrême, dans une SPA, une seule page (P) est chargée et l'utilisateur ne la quitte pas. L'utilisateur interagît avec cette page de manière complexe et l'affichage peut changer complètement. Ces interactions sont gérées en JS avec des appels AJAX (A) fréquents.

Dans une SPA, certaines fonctionnalités du navigateur, comme le bouton retour arrière / avant et l'ouverture d'un lien dans un autre onglet,...), posent problème.

Rendu déclaratif

Une grande différence entre Vue.js et ce qu'on a fait précédemment, est l'approche « déclarative ».

Jusqu'à présent, on partait d'une page HTML et on la modifiait à partir du JS quand l'utilisateur interagissait (click, clavier, ...).
En pratique, une page HTML est généralement construite (par exemple en PHP) à partir de données.
Quand les interactions JS deviennent importantes, on se retrouve à reconstruire en JS une bonne partie du HTML à partir de données modifiées:
données => HTML <= modification des données et du HTML par JS
On construit donc le HTML de deux manières très différentes. Ça conduit à des incohérences. Par ailleurs, modifier du HTML en JS est beaucoup plus compliqué que d'écrire du HTML.

Dans une approche déclarative, on décrit une seule fois comment construire le HTML à partir des données. Quand les données changent, la page se met à jour automatiquement. On a donc:
donnés => HTML

Prenons un exemple très très simple:
La donnée est « age », et on on veut la faire passer de 25 à 26 quand l'utilisateur clique sur un bouton.

Approche classique:

PHP:

$age=25;
echo '<h1>Age: '.$age.'<h1>';
echo '<input type="button" value="bouton"/>';

Ensuite, en JS:

document.querySelector('input').addEventListener('click',()=>{
    document.querySelector('h1').textContent='Age:'+26;
});

En JS, on a voulu changer l'age, on a donc du retrouver le h1 et le modifier. Ce code JS est compliqué par rapport à l'écriture du HTML.
Si les propriétaires veulent maintenant afficher « Mon age est: 25 » au lieu de « Age: 25 », le développeur va devoir changer à la fois le code PHP et le code JS. S'il oublie l'un où l'autre, ce sera incohérent.

Approche déclarative:
En Vue.js:
...
let age=ref(25);
function changer(){
age.value=26;
}

template:

<h1>Age: {{age}}</h1>
<input type="button" value="bouton" @click="changer"/>

Quand l'utilisateur clique sur le bouton, la fonction « changer » change uniquement la variable age. La page se met automatiquement à jour. Aucun besoin d'écrire du JS compliqué pour modifier le DOM. Si les propriétaires de la page veulent maintenant afficher « Mon age est: 25 » au lieu de « Age: 25 », le développeur va juste modifier le template, ce qui est relativement simple.

Conclusions:
  • Avec Vue.js, dans la partie JS, on ne manipule en général pas le DOM. On se contente de modifier les données.
  • Quand on modifie des données, Vue.js doit se rendre compte que ces données ont changé pour mettre à jour la page.
    Les variables, comme « age » sont dites « réactives »: elles font réagir l'interface.


npm run dev

Tapez la commande

$ npm run dev

Ceci lance un serveur de développement et affiche son URL : http://locahost:5173 (Attention: ce numéro de port - 5173 - peut changer)

Ouvrez l'URL affichée.

Et voila ! Votre première App Vue.js 😊

Avec ce serveur de développement, appelé « vite », quand vous modifiez le code, la page se recharge toute seule!

SFC: Single File Component

App.vue est un fichier « .vue » avec trois parties:

En Vue.js, votre application est construite avec des « composants ». Chaque fichier « .vue » est un composant.
Il contient tout ce qu'il faut pour que ce composant marche (JS, HTML, CSS).

Du JS dans le template

Dans un <template>, on veut écrire du HTML qui affiche des données.
Il y a deux types d'endroits où on peut afficher des variables et même des expressions JS:

  1. le contenu d'une balise
  2. les attributs

Dans le contenu (« texte ») d'une balise, on utilise {{ ... code JS ... }} :

<template>
   <h1>Hello {{nom}}, {{1+1}}, {{nom+123}}</h1>
</template>

Essayez dans App.vue

Dans un attribut d'une balise, on utilise « : » devant le nom de l'attribut. La valeur de l'attribut est alors considérée comme du JS:

<template>
   <h1>Hello {{nom}}</h1>
<input type="button" :value="nom" />
<input type="button" :value="'hello'+nom"/>
</template>
Essayez dans App.vue


Événements

Pour gérer les événements on ajoute un attribut avec un « @ » suivi du nom de l'événement.
Pour l'instant, la valeur de l'attribut sera juste le nom de la fonction.

<script setup>
let nom='Tom';

function exemple(){
console.log('ca marche!');
}

function exemple2(e){
console.log('input',e.target.value);
}
</script>

<template>
<h1 @click="exemple">Hello {{nom}}</h1>
<input @keyup="exemple2" />
</template>

Essayez dans App.vue

Réactivité

Dans cet exemple, l'affichage de « Hello Tom » n'est pas mis à jour quand on fait nom='Leila'

<script setup>
let nom='Tom';

function exemple(){
console.log('click');
nom='Leila';
}
</script>

<template>
<h1 @click="exemple">Hello {{nom}}</h1>
</template>

En effet, Vue.js ne sait pas que la variable « nom » a changé. Il ne sait donc pas qu'il faut mettre à jour l'affichage.

Pour que Vue.js le sache, on doit crée des variables réactives. C'est un concept important.

Variables réactives:
ref()
<script setup>
import {ref,reactive} from 'vue';
let nom=ref('Tom');

function exemple(){
console.log('click');
nom.value='Leila';
}
</script>

<template>
<h1 @click="exemple">Hello {{nom}}</h1>
</template>

Essayez dans App.vue. Cliquez sur le <h1>

reactive()
<script setup>
import {ref,reactive} from 'vue';
let user=reactive({nom:'Tom',age: 25});

function exemple(){
console.log('click');
user.nom='Leila';
}
</script>

<template>
<h1 @click="exemple">Hello {{user.nom}}, Age: {{user.age}}</h1>
</template>
Essayez dans App.vue. Cliquez sur le <h1>


JS directement dans l'attribut événement

Pour l'instant, on a mis le nom d'une fonction dans l'attribut événement (@click, @keyup, ...).

   function touche(){ ... }
    ...
   <input @keyup="touche" />

On peut aussi y mettre directement du code JS. On peut y utiliser des variables ref() sans « .value ». Par exemple:

<input type="button" @click="c++" />
Le code JS peut être une fonction fléchée:
<input @keyup="e=>nom=e.target.value" />
Pour accéder directement à l'événement, il y a une variable spéciale « $event »:
  Nom: <input @keyup="nom=$event.target.value" />
On ne peut pas, malheureusement, utiliser directement console.log, ni alert:
  Nom: <input @keyup="console.log('ceci ne sera pas affiché')" />

Voici un exemple complet. Essayez-le.

<script setup>
import {ref,reactive} from 'vue';
let c=ref(0);
let nom=ref('Tom');
</script>

<template>
<p>Le joueur {{nom}} a {{c}} points.</p>
<p>Le joueur {{nom}} a fini le niveau 3.</p>
<p>Le joueur {{nom}} est classé 4e.</p>
Nom: <input @keyup="e=>nom=e.target.value" />
Nom: <input @keyup="nom=$event.target.value" />
<input type="button" @click="c++" value="cliquer"/>
</template>

<style scoped>
</style>

Boucle v-for

On veut souvent afficher une suite de choses dans un template.  On a donc besoin de boucles.
Vue.js permet de faire différentes sortes de boucles en utilisant l'attribut « v-for ».
Voyons une boucle très simple:

<template>
   <span v-for="i in 10">Hello {{i}}</span>
</template>

Cette boucle crée 10 <span>. Attention, la valeur « i » va de 1 à 10 (et non pas de 0 à 9).


Sujet 8

v-if

L'attribut « v-if » permet d'inclure un élément HTML de manière conditionnelle.
Par exemple:

<script setup>
let condition=true;
</script>
<template>
<p v-if="condition">Bonjour!</p>
</template>

Le paragraphe ce sera inclus que si la variable condition est vraie.
On peut, bien entendu, mettre du JS dans la condition:

<script setup>
let age=25;
</script>
<template>
<p v-if="age>=18">Bonjour!</p>
</template>

Attribut :class objet

On a souvent besoin d'indiquer plusieurs classes sur une balise dans le template.
La présence de ces classes dépend souvent de conditions.
On peut alors utiliser un objet JS pour indiquer quelles classes inclure.

Cet exemple:

<template>
    <p :class="{urgent: true, important: false}">Bonjour</p>
</template>

Donnera

   <p class="urgent">Bonjour</p>