Pour votre progression, c'est très important de finir le sujet précédent avant de commencer celui-ci.
Vous devez travailler connectés (lien « Connexion » en haut à droite de la page). Sinon, vous rencontrerez des problèmes d'avancement et vous risquez d'être comptés absent. En étant connectés vous retrouverez l'endroit où vous en étiez à la séance suivante.
Commençons par une rapide révision des notions des sujets précédents.
Quelles affirmations sont vraies ?
Dans une SPA, quand l'utilisateur clique quelque part, il ne change pas de page.
Les requêtes AJAX sont en général plus fréquentes sur une page web classique que sur une SPA.
Le JS est indispensable dans une page web classique
Le JS est indispensable dans une SPA
Dans une SPA, il est plus difficile de gérer le bouton arrière du navigateur. La possibilité d'ouvrir des choses dans d'autres onglets est aussi plus délicate.
Quelles affirmations sont vraies ?
2) à partir du JS, par exemple, lors des interactions (clavier, souris)
En Vue.js, on crée d'abord une page HTML à l'aide d'un template, puis, ensuite, on modifie le DOM à partir du JS, par exemple, lors des interactions (souris, clavier...).
En Vue.js on écrit un template qui contient des variables. Dans la partie JS, on se contente de modifier ces variables et l'affichage se reconstruit automatiquement à partir du template.
Quelle commande faut-il taper, dans le terminal, pour démarrer le serveur de développement pour Vue.js ?
Le serveur de développement est celui qui vous permettra de vous connecter sur http://locahost:5173 pour voir votre site Vue.js
Vous êtes sur la bonne voie. Il s'agit bien d'une commande qui commence par « npm ... »
Presque! Il s'agit bien d'une commande qui commence par « npm run ... »
En Vue.js on écrit la plupart du code dans des fichier Single FIle Component (SFC).
Que est l'extension utilisée pour ces fichiers ?
(L'extension est la fin du nom de fichier. Par exemple, l'extension pour « photo.jpg » est « jpg »)
Quelles sont les différentes parties d'un fichier .vue ?
<script setup>
<template>
<style>
<title>
<variables>
<head>
<vue>
<code>
<css>
<miaou>
<script setup>Que faut-il écrire à la place de XYZ pour afficher « Le chat dit miaou » ou « Le chat dit ronron » en utilisant la variable « son » ?
let son="miaou";
if(Math.random()>.5){son="ronron";}
</script>
<template>
<p>XYZ</p>
</template>
Presque! La réponse contient bien :
{{son}}
Vérifiez le reste
Vous êtes sur la bonne voie. Vous avez écrit:
{son}
C'est presque ça, il manque des choses.
<script setup>
function ma_fonction(){
console.log('ma_fonction');
}
</script>
<template>
<p XYZ>Bonjour</p>
</template>
Que faut-il écrire à la place de XYZ pour que la fonction « ma_fonction » soit appelée quand l'utilisateur clique sur le paragraphe ?
<script setup>
let age=20;
function ma_fonction(){
age=21;
}
</script>
<template>
<p @click="ma_fonction">Leila a {{age}} ans.</p>
</template>
Quelles affirmations sont vraies ?
Quand l'utilisateur clique sur le paragraphe, l'affichage ne change pas.
Quand l'utilisateur clique sur le paragraphe, il affiche « Leila a 21 ans. »
Quand l'utilisateur clique sur le paragraphe, la variable age prend la valeur 21.
Quand l'utilisateur clique sur le paragraphe, ma_fonction est appelée
<script setup>
ABC
let age=DEF;
function ma_fonction(){
GHI
}
</script>
<template>
<p @click="ma_fonction">Leila a {{age}} ans.</p>
</template>
On voudrait que le paragraphe affiche « Leila a 21 ans. » quand l'utilisateur clique dessus.
Il faut modifier ABC, DEF et GHI.
Commençons par ABC.
Que faut-il écrire à la place de ABC ?
Vous êtes sur la bonne voie. La réponse commence bien par « import » et contient bien aussi « vue ».
« import » permet d'utiliser une librairie.
Il manque des choses et vérifiez la syntaxe.
Vous êtes sur la bonne voie. La réponse commence bien par « import ».
« import » permet d'utiliser une librairie.
<script setup>
import {ref,reactive} from 'vue';
let age=DEF;
function ma_fonction(){
GHI
}
</script>
<template>
<p @click="ma_fonction">Leila a {{age}} ans.</p>
</template>
On voudrait que le paragraphe affiche « Leila a 21 ans. » quand l'utilisateur clique dessus.
Il faut modifier ABC, DEF et GHI.
Que faut-il écrire à la place de DEF pour créer une variable qui vaille 20 et qui soit adaptée à la situation ?
<script setup>
ABC
let age=DEF;
function ma_fonction(){
GHI
}
</script>
<template>
<p @click="ma_fonction">Leila a {{age}} ans.</p>
</template>
On voudrait que le paragraphe affiche « Leila a 21 ans. » quand l'utilisateur clique dessus.
Il faut modifier ABC, DEF et GHI.
Que faut-il écrire à la place de GHI pour que l'age devienne 21 ?
Non. La variable « age » est un « ref ». Vous ne devez pas écrire directement dedans...
Vous êtes sur la bonne voie. La réponse commence bien par « age.value »
<script setup>
import {ref,reactive} from 'vue';
let user=XYZ;
function ma_fonction2(){
user.age=30;
}
</script>
<template>
<p @click="ma_fonction2">L'utilisateur {{user.nom}} a {{user.age}} ans.</p>
</template>
Que faut-il écrire à la place de XYZ pour créer un objet ayant deux propriétés nom et age (dans cet ordre) ayant pour valeurs 'Tom' et 20 respectivement.
Quand l'utilisateur clique sur le paragraphe, l'affichage doit être mis à jour.
Non, ref(...) est utilisé pour les valeurs qui ne sont pas des objets ou des tableaux.
<script setup>
</script>
<template>
<ul>
<li XYZ>{{n}}x5={{5*n}}</li>
</ul>
</template>
<style scoped>
</style>
Que faut-il écrire à la place de XYZ pour afficher la table de multiplication par 5 pour les nombres allant de 1 à 20.
Le résultat devrait être:
<ul>
<li>1x5=5</li>
<li>2x5=5</li>
<li>3x5=5</li>
...
<li>19x5=95</li>
<li>20x5=100</li>
</ul>
Vous êtes sur la bonne voie. La réponse commence bien par « v-for ».
Dans votre projet vue:
Créez un répertoire « assets » à l'intérieur du répertoire « src ».
Dans « assets », enregistrez les images suivantes dans votre projet vue:
piece-chat.svg:
piece-souris.svg:
texture-grise.jpg:
cadre.svg:
Reprenons le tableau fait au Sujet-7 et ajoutons un peu de CSS.
Mettez votre fichier App.vue à jour:
Le <script> et le <template> n'ont pas changé, uniquement le CSS:
<script setup>
import {ref,reactive} from 'vue';
let tableau=[
['c','' ,'' ,'' ,'' ,'' ,'s'],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['s','' ,'' ,'' ,'' ,'' ,'c'],
];
</script>
<template>
<table>
<tr v-for="ligne in 6">
<td v-for="colonne in 7">{{tableau[ligne-1][colonne-1]}}</td>
</tr>
</table>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
Ajoutons dans le template, deux blocs, à gauche et à droite, pour représenter les joueurs:
Ajoutons une pièce en haut «piece-active ».
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" src="/src/assets/piece-chat.svg"/>
<table>
<tr v-for="ligne in 6">
<td v-for="colonne in 7">
{{tableau[ligne-1][colonne-1]}}
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
Dans le script, écrivez une fonction appelée « mouvement_tableau » qui affiche « mouvement » dans la console.
Que faut -il écrire à la place de XYZ pour appeler cette fonction « mouvement_tableau » chaque fois que l'utilisateur déplace la souris sur le tableau ?
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" src="/src/assets/piece-chat.svg"/>
<table XYZ>
<tr v-for="ligne in 6">
<td v-for="colonne in 7">
{{tableau[ligne-1][colonne-1]}}
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
Ajoutez un paramètre « event » à la fonction « mouvement_tableau » et faites en sorte que l'image « piece-active » se déplace horizontalement quand l'utilisateur déplace la souris sur le tableau. (corrigez aussi le décalage)
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
<script setup>
import {ref,reactive} from 'vue';
let tableau=[
['c','' ,'' ,'' ,'' ,'' ,'s'],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['s','' ,'' ,'' ,'' ,'' ,'c'],
];
let positionPiece=ref(0);
function mouvement_tableau(event){
console
positionPiece.value=event.pageX-30;
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" src="/src/assets/piece-chat.svg"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7">
{{tableau[ligne-1][colonne-1]}}
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
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>
Dans le tableau JS, remplacez 'c' par 'chat' et 's' par 'souris'
Maintenant, dans le template, on voudrait afficher une image de la pièce chat / souris en fonction de la valeur de la case.
Mais on ne peut afficher une image, que si la la case n'est pas vide, c'est à dire si la case correspondante dans le tableau JS n'est pas une chaîne vide.
Ajoutez une image dans le <td>.
En utilisant v-if et en utilisant du JS pour l'attribut « src », affichez l'image de la pièce correspondante.
(N'oubliez pas que les boucles v-for sont numérotées à partir de 1, contrairement aux tableaux JS.)
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
<script setup>
import {ref,reactive} from 'vue';
let tableau=[
['chat','' ,'' ,'' ,'' ,'' ,'souris'],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['souris','' ,'' ,'' ,'' ,'' ,'chat'],
];
let positionPiece=ref(0);
function mouvement_tableau(event){
console
positionPiece.value=event.pageX-30;
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" src="/src/assets/piece-chat.svg"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
Quand l'utilisateur clique sur le <td> appelez une fonction « click_td » en lui passant comme paramètres la ligne et la colonne (-1) .
Créez cette fonction et affichez y la ligne et la colonne cliquée dans la console.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
<script setup>
import {ref,reactive} from 'vue';
let tableau=[
['chat','' ,'' ,'' ,'' ,'' ,'souris'],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['souris','' ,'' ,'' ,'' ,'' ,'chat'],
];
let positionPiece=ref(0);
function mouvement_tableau(event){
console
positionPiece.value=event.pageX-30;
}
function click_td(ligne,colonne){
console.log(ligne,colonne);
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" src="/src/assets/piece-chat.svg"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7" @click="click_td(ligne-1,colonne-1)">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
Pour l'instant notre tableau JS n'est pas reactif:
const tableau=([
['','','','','','',''],
....
C'est à dire, que si on le modifie, Vue.js ne s'en rendra pas compte et ne mettra pas à jour l'affichage.
Rendez- ce tableau réactif.
Supprimez tous les chats et souris présents dans le tableau.
Dans click_td, écrivez une petite boucle qui parcours le tableau de haut en bas pour trouver la première ligne libre (imaginez qu'il y a déjà des pièces dans le tableau JS).
Ajoutez une pièce 'chat' à cet endroit.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
<script setup>
import {ref,reactive} from 'vue';
let tableau=reactive([
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
]);
let positionPiece=ref(0);
function mouvement_tableau(event){
positionPiece.value=event.pageX-30;
}
function click_td(ligne,colonne){
let ligneLibre=false;
for(let l=5;l>=0;l--){
if(tableau[l][colonne]===''){ligneLibre=l;break;}
}
if(ligneLibre===false){return;}
tableau[ligneLibre][colonne]='chat';
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" src="/src/assets/piece-chat.svg"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7" @click="click_td(ligne-1,colonne-1)">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
Tous ces chats s'ennuient ... et ont faim.
Ajoutez une variable « joueur » qui vaut initialement « chat » et changez là à chaque click.
Faites en sorte que:
<script setup>
import {ref,reactive} from 'vue';
let joueur=ref('chat');
let tableau=reactive([
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
]);
let positionPiece=ref(0);
function mouvement_tableau(event){
positionPiece.value=event.pageX-30;
}
function click_td(ligne,colonne){
let ligneLibre=false;
for(let l=5;l>=0;l--){
if(tableau[l][colonne]===''){ligneLibre=l;break;}
}
if(ligneLibre===false){return;}
tableau[ligneLibre][colonne]=joueur.value;
if(joueur.value==='chat'){joueur.value='souris';}else{joueur.value='chat';}
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" class="joueur">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" :src="'/src/assets/piece-'+joueur+'.svg'"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7" @click="click_td(ligne-1,colonne-1)">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</td>
</tr>
</table>
<div id="joueur-souris" class="joueur">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
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>
Utilisez les objets dans les classes pour ajouter la class « actif » au div « joueur-chat » si le joueur est actuellement le chat.
Faites la même chose pour la souris.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur,
puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
<script setup>
import {ref,reactive} from 'vue';
let joueur=ref('chat');
let tableau=reactive([
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
['' ,'' ,'' ,'' ,'' ,'' ,'' ],
]);
let positionPiece=ref(0);
function mouvement_tableau(event){
positionPiece.value=event.pageX-30;
}
function click_td(ligne,colonne){
let ligneLibre=false;
for(let l=5;l>=0;l--){
if(tableau[l][colonne]===''){ligneLibre=l;break;}
}
if(ligneLibre===false){return;}
tableau[ligneLibre][colonne]=joueur.value;
if(joueur.value==='chat'){joueur.value='souris';}else{joueur.value='chat';}
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" :class="{joueur:true, actif:joueur==='chat'}">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" :src="'/src/assets/piece-'+joueur+'.svg'"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7" @click="click_td(ligne-1,colonne-1)">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</td>
</tr>
</table>
<div id="joueur-souris" :class="{joueur:true, actif:joueur==='souris'}">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>
Pour animer la chute de la pièce, on peut utiliser une transition CSS. C'est un peu compliqué en Vue.js.
Entourez la pièce dans le tableau par <Transition...>:
<Transition name="trans-piece">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</Transition>
Uniquement si vous avez tout fini et si vous êtes en avance:
Écrivez un algorithme qui détermine si 4 pièces sont alignées.
Affichez un alert avec le gagnant.
<script setup>
import {ref,reactive} from 'vue';
let joueur=ref('chat');
const tableau=reactive([
['','','','','','',''],
['','','','','','',''],
['','','','','','',''],
['','','','','','',''],
['','','','','','',''],
['','','','','','',''],
]);
let positionPiece=ref(0);
function mouvement_tableau(event){
positionPiece.value=event.pageX-30;
}
function click_td(ligne,colonne){
let ligneLibre=false;
for(let l=5;l>=0;l--){
if(tableau[l][colonne]===''){ligneLibre=l;break;}
}
if(ligneLibre===false){return;}
tableau[ligneLibre][colonne]=joueur.value;
if(verifier_gagner(joueur.value,ligneLibre,colonne)){
let j=joueur.value;
setTimeout(()=>alert(j+' a gagné'),550);
}
if(joueur.value==='chat'){joueur.value='souris';}else{joueur.value='chat';}
}
function verifier_gagner(j,ligne,colonne){
let dx,dy;
// A partir de la position actuelle, vérifier dans les 4 directions:
// verticale, horizontale, diagonale, diagonale inverse
for([dx,dy] of [[0,1],[1,0],[1,1],[1,-1]]){
let x,y;
// Remonter en sens inverse de la direction (-dx,-dy).
for(x=colonne,y=ligne;x>=0 && y>=0 && y<6 && tableau[y][x]===j;x-=dx,y-=dy);
x+=dx;
y+=dy;
// Compter le nombre de pieces dans la direction (dx,dy).
let ct=0;
for(;x<7 && y<6 && y>=0 && tableau[y][x]===j;x+=dx,y+=dy){ct++;}
if(ct>=4){return true;}
}
}
</script>
<template>
<div id="jeu">
<div id="joueur-chat" :class="{joueur:true, actif:joueur==='chat'}">
<h2>Chat</h2>
<img src="./assets/piece-chat.svg"/>
</div>
<img id="piece-active" :style="'left:'+positionPiece+'px'" :src="'/src/assets/piece-'+joueur+'.svg'"/>
<table @mousemove="mouvement_tableau">
<tr v-for="ligne in 6">
<td v-for="colonne in 7" @click="click_td(ligne-1,colonne-1)">
<Transition name="trans-piece">
<img v-if="tableau[ligne-1][colonne-1]!==''"
:src="'/src/assets/piece-'+tableau[ligne-1][colonne-1]+'.svg'"/>
</Transition>
</td>
</tr>
</table>
<div id="joueur-souris" :class="{joueur:true, actif:joueur==='souris'}">
<h2>Souris</h2>
<img src="./assets/piece-souris.svg"/>
</div>
</div>
</template>
<style scoped>
#jeu{
display: flex;
margin-top: 100px;
}
#piece-active{
position: absolute;
left: 100px;
top: 20px;
}
.joueur{
width: 100px;
height: 200px;
margin:10px;
margin-top:100px;
background-color: blue;
color: white;
border-radius: 10px;
font-family: sans;
padding: .5em;
text-align: center;
box-shadow: 2px 2px 2px rgba(0,0,0,.5);
}
.joueur.actif{
background-color: #55f;
}
.joueur h2{
font-size: 18px;
}
table{
padding: 25px;
padding-top: 27px;
padding-bottom: 23px;
background-image: url(assets/cadre.svg);
border-collapse: separate;
border-spacing: 0;
}
td {
text-align: center;
width: 68px;
height: 68px;
}
table img{
position: relative;
transition: top .5s ease-in;
top: 0;
z-index: -1;
}
#jeu tr:nth-child(1) .trans-piece-enter-from{top: -110px;}
#jeu tr:nth-child(2) .trans-piece-enter-from{top: -180px;}
#jeu tr:nth-child(3) .trans-piece-enter-from{top: -250px;}
#jeu tr:nth-child(4) .trans-piece-enter-from{top: -320px;}
#jeu tr:nth-child(5) .trans-piece-enter-from{top: -390px;}
#jeu tr:nth-child(6) .trans-piece-enter-from{top: -460px;}
</style>