Sujet 8

  1. Bienvenue au 8e sujet
  2. Révisions
    1. SPA
    2. Rendu déclaratif
    3. Démarrer le serveur de développement
    4. Fichier SFC
    5. Parties d'un fichier .vue
    6. Syntaxe template texte
    7. Cliquer
    8. Modifier variable
    9. Variables ABC
    10. Variables DEF
    11. Variables GHI
    12. user
    13. boucle
  3. Puissance chat
    1. Fichier App.vue
    2. Joueurs
    3. Mouvement
    4. piece-active
    5. Correction
    6. v-if
    7. Image piece
    8. Correction
    9. click_td
    10. Correction
    11. click_td, suite
    12. Correction
    13. Changement de joueur
    14. Correction
    15. Attribut :class objet
    16. Blocs joueurs
    17. Correction
    18. Améliorations
    19. Correction

1. Bienvenue au 8e sujet

1.1 Bienvenue au 8e sujet

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.

2. Révisions

2.1 Révisions

Commençons par une rapide révision des notions des sujets précédents.

Révisions

2.2 SPA

Quelles affirmations sont vraies ?

Révisions

2.3 Rendu déclaratif

Quelles affirmations sont vraies ?

Révisions

2.4 Démarrer le serveur de développement

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

Révisions

2.5 Fichier SFC

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 »)

Révisions

2.6 Parties d'un fichier .vue

Quelles sont les différentes parties d'un fichier .vue ?

Révisions

2.7 Syntaxe template texte


<script setup>
let son="miaou";
if(Math.random()>.5){son="ronron";}
</script>
<template>
<p>XYZ</p>
</template>
Que faut-il écrire à la place de XYZ pour afficher « Le chat dit miaou » ou « Le chat dit ronron » en utilisant la variable « son » ?

Révisions

2.8 Cliquer

<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 ?

Révisions

2.9 Modifier variable

<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 ?

Révisions

2.10 Variables ABC

<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 ?

Révisions

2.11 Variables DEF

<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 ?

Révisions

2.12 Variables GHI

<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 ?

Révisions

2.13 user

<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.

Révisions

2.14 boucle

<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>


3. Puissance chat

3.1 Puissance chat

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:


Puissance chat

3.2 Fichier App.vue

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>


Puissance chat

3.3 Joueurs

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>



Puissance chat

3.4 Mouvement

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>



Puissance chat

3.5 piece-active

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:

Puissance chat

3.6 Correction

<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>

Puissance chat

3.7 ¤ 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>

Puissance chat

3.8 Image piece

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:

Puissance chat

3.9 Correction

<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>

Puissance chat

3.10 click_td

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:

Puissance chat

3.11 Correction

<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>

Puissance chat

3.12 click_td, suite

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:

Puissance chat

3.13 Correction

<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>

Puissance chat

3.14 Changement de joueur

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:

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Puissance chat

3.15 Correction

<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>

Puissance chat

3.16 ¤ 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>


Puissance chat

3.17 Blocs joueurs

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:

Puissance chat

3.18 Correction

<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>

Puissance chat

3.19 Améliorations

Animation

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>
Vérification gagnant

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.

Puissance chat

3.20 Correction

<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>