Skip to content

Latest commit

 

History

History
1021 lines (768 loc) · 15 KB

slides.md

File metadata and controls

1021 lines (768 loc) · 15 KB
theme class highlighter lineNumbers info drawings layout counts download
default
text-center
shiki
false
## Slidev Starter Template Presentation slides for developers. Learn more at [Sli.dev](https://sli.dev)
persist
center
0
true

Vue.js

One framework to rule them all


Pourquoi Vue.js ?


layout: two-cols

Pourquoi un framework?

Avant

HTML

<input class="name" value="" />
<p class="result"></p>

Javascript

const input = document.querySelector(".name");
const result = document.querySelector(".result");

input.addEventListener("change", (event) => {
  const newValue = event.target.value;
  result.textContent += newValue;
});

::right::


Maintenant

HTML

<input class="name" v-model="result" />
<p>{{ result }}</p>

Javascript

data() {
  return {
    result: '',
  }
}
<style> pre { @apply mr-10; } </style>

layout: two-cols

La philosophie Vue.js

  • DOM virtuel de composants
  • Réutilisation simplifiée de logique à travers une App
  • Manipulation plus simple des interfaces (ou des "Vues")
<!-- DOM html -->
<html>
  <body>
    <header>
      Navbar
    </header>
    <div>
      <form id="formulaireInscription">
        <label for="name">Name</label>
        <input name="name" />
        ...
      </form>
    </div>
    <footer>
      Contact
    </footer>
  </body>
</html>

::right::

// DOM Vue
<App>
  <Layout theme="dark">
    <FormulaireInscription />
  </Layout>
</App>
<style> pre { margin-right: 5px; } .slidev-layout { font-size: 0.9rem; } .last-space { margin-top: 133.5px; margin-left: 5px; } li { list-style: circle; } </style>

layout: two-cols

Les composants

Pour un code réutilisable

<!-- MonComposant.vue -->
<template>
  <input class="myInput" v-model="result" />
  <span> {{ result }} </span>
</template>

<script>
  import { defineComponent } from "vue";

  export default defineComponent({
    data() {
      return {
        result: "",
      };
    },
  });
</script>

<style>
  .myInput { background-color: gray; }
</style>

::right::


Exemple




Et pour l'utiliser?

<MonComposant />

// ou

<mon-composant />
On peut réutiliser ce composant ou on veut sans avoir besoin de réecrire sa logique et sa structure à chaque fois.
<style> pre { @apply mr-5; } h2 { @apply text-[#41b883] } </style>

A vous de jouer !

En utilisant le template d'application Vue fourni, créez le composant de la slide précédente.

Ce composant contient une donnée result qui est liée à un input qui prend votre entrée et l'affiche dans un span.


--- layout: two-cols ---

Directives

v-if


<template>
  <input v-model="name">
  <span v-if="name === 'bob'"> {{ name }} </span>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  data: () => {
    return {
      name: 'toto',
    }
  },
})
</script>

::right::


layout: two-cols

v-for

<template>
  <ul>
    <li v-for="legume in legumes" :key="legume"> 
      {{ legume }} 
    </li>
  </ul>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  data: () => {
    return {
      legumes: ['tomate', 'oignon', 'carotte']
    }
  }
});
</script>

::right::


layout: two-cols

v-on

<template>
  <button v-on:click="counter++">Incrémenter</button>
  <span> {{ counter }} </span>
</template>

Syntaxe simplifiée (à utiliser):

<template>
  <button @click="counter++">Incrémenter</button>
  <span> {{ counter }} </span>
</template>

Script :

export default defineComponent({
  data: () => {
    return {
      counter: 0,
    }
  }
});

::right::


layout: default

v-bind

La base des directives, la must have

Permet de lier une data à un élément du template.

Exemple :

<template>
  <img v-bind:src="imgUrl">
  <!-- ou plus simplement -->
  <img :src="imgUrl">
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  data: () => {
    return {
      imgUrl: 'https://...',
    },
  },
})
</script>

layout: default

A vous !

Créez un composant qui contient : une liste de noms, un input et un bouton.

1 - Au clic sur le bouton, ajouter le contenu de l'input dans la liste.
2 - Ajouter une condition sur la liste, pour ne l'afficher uniquement que lorsqu'elle contient 3 éléments.


layout: default

Les options d'un composant

  • Options de données :

    • data
    • computed
    • props
  • Options de mutations de données :

    • methods
  • Options de cycle de vie :

    • created
    • mounted
    • setup

Il y en a d'autres, mais pour l'instant, on va se limiter à ceux là

layout: two-cols

Computed

<template>
  <input v-model="nom" placeholder="nom"/>
  <input v-model="prenom" placeholder="prenom"/>
  <p>{{ fullName }}</p>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  data() {
    return {
      nom: '',
      prenom: ''
    }
  },
  computed: {
    fullName() {
      return `${this.nom} ${this.prenom}`; 
    }
  }
})
</script>

::right::


layout: default

Methods

Tout simplement, des fonctions utilisables uniquement par le composant.

<template>
  <button @click="increment">Incrémenter</button>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  data() {
    return {
      counter: 0,
    }
  },
  methods: {
    increment() {
      this.counter++;
    }
  }
});
</script>

layout: default

Watchers

Vue is watching you

import { defineComponent } from 'vue';

export default defineComponent({
  data: () => {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar',
  },
  watch: {
    firstName: function (newVal) {
      this.fullName = `${newVal} ${this.lastName}`;
    },
    lastName: function (newVal) {
      this.fullName = `${this.firstName} ${newVal}`;
    },
  }
})

layout: center

Communication


Communiquer avec un composant

Deux types de communication :

  • Parent Enfant
  • Enfant Parent
<style> li { list-style: circle; } </style>

Communication Parent-Enfant

Props

Le composant :

<template>
  <span>{{ numero }}</span>
</template>

<script>
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    numero: Number,
  },
});
</script>

L'appel depuis le parent :

<MonComposant numero="9"/>

layout: two-cols

Communication Enfant-Parent

Events:

Dans l'enfant :

<template>
  <button @click="sendDataToParent(data)">
    Alert parent
  </button>
</template>
<script>
import { defineComponent } from 'vue';

export default defineComponent({
  emits: ['update-data'],
  methods: {
    sendDataToParent(data) {
      this.$emit('update-data', data);
    }
  }
});
</script>

::right::

Dans le parent :

<template>
  <composant-enfant @updateData="handleChildData"/>
</template>
<script>
import { defineComponent } from 'vue';

export default defineComponent({
  methods: {
    handleChildData(data) {
      console.log(data);
    }
  }
})
</script>
<style> pre { margin-right: 5px; } .last-space { margin-top: 92px; margin-left: 5px; } </style>

layout: default

Encore à vous

Créez un composant Calculatrice, qui contient un composant EcranCalculatrice permettant d'afficher le résultat de la calculatrice ainsi que les opérations.

Créez également un composant BoutonCalculatrice qui contiendra soit un numéro soit un opérateur mathématique (+, -, /, *). Ce composant servira à créer le clavier de la calculatrice.

Le composant devra donc implémenter la logique pour les deux cas et réaliser les bonnes actions en conséquence.


layout: two-cols

Cycle de vie des composants

  • setup
  • created
  • mounted
  • updated

::right::


layout: two-cols

Routing

  • Utilisation de vue-router
  • Permet de synchroniser les URL avec des composants
  • Gestion fine de la navigation grâce à des paramètres

::right::


layout: two-cols

Configuration de router

On crée notre fichier de routing, routing.js :

import { 
  createRouter, 
  createWebHistory 
} from 'vue-router'
import HomeView from '../views/HomeView.vue'
import About from '../views/About.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    { path: '/', name: 'home', component: HomeView },
    { path: '/about', name: 'about', component: About }
  ]
})

export default router

::right::

Dans le main.js de notre application :

import App from './App.vue'
import router from './router'

const app = createApp(App)

app.use(router)

app.mount('#app')

Et dans votre App.vue :

<template>
  <RouterView />
</template>
<style> pre { margin-right: 15px; } .last-space { margin-top: 56px; margin-left: 5px; } </style>

layout: default

Gestion de paramètres

Paramètres dans l'URL :

const routes = [
  { path: '/users/:id', component: User },
]

Paramètres en props du composant :

const routes = [
  // Le paramètre id dans l'URL va être passé comme props
  // au composant User
  // Par exemple : http:localhost/users/1 , va passer 1
  // comme id au composant User
  { path: '/users/:id', component: User, props: true },
]

layout: two-cols

Liens de navigation

Dans le template

<RouterLink to="/about">About</RouterLink>

::right::

Programmatiquement

export default {
  ...,
  methods: {
    goToAboutState() {
      // Pour naviguer avec le nom: 
      this.$router.push({
        name: 'about'
        // On peut passer des paramètres ici
      });

      // Pour naviguer avec le path :
      this.$router.push({
        path: '/about'
        // On peut passer des paramètres ici
      });
    },
  },
}
<style> pre { margin-right: 15px; } .last-space { margin-top: 56px; margin-left: 5px; } </style>

layout: default

On test !

Configurez votre application pour prendre deux routes, une route d'accueil et une route qui affichera un exercice des TP précédents de votre choix.

Pour savoir comment ajouter un router sur votre application, regardez la section "Routing" du cours en ligne ;)


layout: default

API

Link your app with the world


layout: default

REST API

Les verbes REST à connaître :


  • GET : Pour récupérer des ressources
  • POST : Pour créer des ressources
  • PUT : Pour mettre à jour des ressources
  • DELETE : Pour supprimer des ressources

PS: Il existe encore d'autres verbes qu'on ne verra pas dans ce cours


layout: default

Et en Vue ?

import axios from 'axios';

axios.get('api')

axios.post('api')

// etc

layout: default

Petit tips !

Si vous voulez récupérer des données, faites le pendant la phase mounted de votre composant.

Exemple :

export default {
  mounted() {
    axios.get('api').then((resultat) => {
      // faire ce dont on a besoin du resultat
    })
  }
}

layout: default

Store

Global state management


layout: two-cols

  • Installation de la librairie Vuex :
npm install vuex
  • Configuration du store :
import { createStore } from 'vuex';
const store = createStore({
  state() {
    return {
      counter: 0,
    }
  },
  getters: {
    getCounter: (state) => state.counter, 
  },
  mutations: {
    setCounter(state, payload) {
      state.counter = payload;
    }
  }
});

::right::

  • Ajout à l'app :
import store from './store';

const app = createApp(App);
app.use(store);
  • Utilisation dans un composant :
export default defineComponent({
  computed: {
    counter() {
      return this.$store.getters.getCounter;
    }
  },
  methods: {
    incrementCounterByTwo() {
      this.$store.commit('setCounter', 2);
    }
  }
})
<style> pre { margin-right: 15px; } .last-space { margin-top: 56px; margin-left: 5px; } </style>