Cours 1: introduction à Vue.js
Cours 2: Style (Bulma & class-binding)
Cours 3: Client-side routing
Cours 4: Rest, promises, ouverture
On est maintenant capable de
v-bind, v-if, v-on, v-forQu'est ce qu'il manque à notre application pour être montrable ?
☰ Un menu et une structure en différentes pages
C'est l'objectif de notre séance
Dans toutes vos applications web, vous aurez besoin de servir plusieurs pages, toutes accessibles à une URL différente
C'est ce qu'on appelle le routing. Nous allons découvrir les mécaniques proposés par Vue pour mettre en place le routing de notre application.
Premièrement, ajoutons un menu à notre application. Dans l'esprit de Vue, votre application va être fait de pleins de petits blocs réutilisables appelés composants.
Pour l'instant, on a un composant App pour l'application et un composant Composter pour afficher un composteur.
Crééons un nouveau composant MenuView
Crééons un nouveau composant MenuView
MenuView.vue dans le dossier componentsMenuView.vue, déclarer un template et un script minimal :
<template>
MENU
</template>
App.vue), importer MenuView :
<template>
<div>
<MenuView />
navbar Bulma
Voir commit Exercice 12 pour un exemple de menu responsive animé
On utilise notamment le @click
pour modifier une data mobileMenuActive qui conditionne l'affichage du menu mobile.
AboutPage avec une prop "message" et l'afficher au-dessus de la liste de composteursCompostersList et l'utilisater dans App.vue
Grace aux 2 précédents exercices, on a maintenant un menu et 2 composants séparés (AboutPage et CompostersList)
Je voudrais que mon menu me permette d'afficher l'AboutPage ou la CompostersList dans la div container
Je voudrais que mon menu me permette d'afficher l'AboutPage ou la CompostersList dans la div container
Je voudrais également que l'url de mon app change en fonction du contenu affiché (e.g. /about et /composters)
C'est ce que permet de faire le router Vue
C'est ce que permet de faire le router Vue
Le router vue permet de faire du Client-side Routing (contrairement à la traditionnelle approche du Server-side routing)
Dès que l'on clique sur un lien, une requête est envoyée au serveur et c'est le serveur qui retourne la page à charger
On parle de Server-side Routing parce que le navigateur effectue une requête vers le serveur dès que l'URL change.
Le Server-side Routing a plusieurs inconvénients (mais aussi ses avantages)
C'est pour ces raisons que l'on a mis au point le Client-side routing
Ici le serveur ne va renvoyer qu'une seule fois l'index.html qui inclue tout le code de notre application Vue
Puisque la navigateur a accès à tout le code, quand on change d'URL le Router vue va juste calculer les différences à appliquer sur le DOM, sans faire appel au serveur ni recharger la page.
Server-side routing
Server-side routing
Client-side routing
Single Page Applications (SPA)
Une SPA est une application web qui:
Lors du premier cours, on avait déjà étudié l'index.html
Lors du premier cours, on avait déjà étudié l'index.html
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width,initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but
<%= htmlWebpackPlugin.options.title %>
doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Lors du premier cours, on avait déjà étudié l'index.html
index.html est donc la "single page" de notre Single page Application, dans laquelle tout le code de l'application est monté.
Le router View va se servir de cette page pour effectuer le client-side routing
Étape 1: installer la librarie vue-router
npm install vue-router@4
vue-routerpackage.jsonÉtape 2: définir nos routes
src/router/index.jsimport CompostersList from '../components/CompostersList.vue'
import AboutPage from '../components/AboutPage.vue'
const routes = [
{
path: '/composters',
name: 'CompostersList',
component: CompostersList
},
{
path: '/about',
name: 'About',
component: AboutPage
}
]
Étape 2: définir nos routes
import CompostersList from '../components/CompostersList.vue'
import AboutPage from '../components/AboutPage.vue'
const routes = [
{
path: '/composters',
name: 'CompostersList',
component: CompostersList
},
{
path: '/about',
name: 'About',
component: AboutPage
}
]
Chaque route est définie avec un path (son URL), un name et le component à router
Étape 3: créer le router
import { createRouter, createWebHistory } from 'vue-router'
import CompostersList from '../components/CompostersList.vue'
import AboutPage from '../components/AboutPage.vue'
const routes = [...]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
La méthode createWebHistory permet d'éviter d'avoir des hash dans l'url (voir l'explciation détaillée ici)
Étape 4: brancher le router à l'application
Dans le fichier main.js qui créé et injecte l'application Vue, brancher le router
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App)
.use(router)
.mount('#app')
Étape 5: définir dans quel div le routeur doit rendre le contenu
Dans le fichier App.vue, remplaçons le contenu actuel par:
<MenuView />
<router-view />
/composters, /about, / ? HomePage branché sur l'url /Notre routing fonctionne mais...
La page semble se recharger intégralement quand on clique sur nos liens
Je voudrais indiquer à Vue qu'il n'est pas nécessaire que le navigateur recharge toute la page
Je voudrais indiquer à Vue qu'il n'est pas nécessaire que le navigateur recharge toute la page
C'est l'intérêt du composant router-link (fourni par la librairie vue-router)
Accueil
Accueil
Accueil
Le composant router-link dispose de nombreuses props (voir la liste complète ici)
Il existe de nombreuse façon de définir la route: via une URL, un nom, en ajoutant des paramètres...
A propos
Si la route courante correspond au lien to d'un router-link, ce dernier se voit attribué par défaut la classe css .router-link-active
MenuView pour utiliser des router-link là où ça vous semble pertinentVous serrez probablement amenés à devoir définir des URLs contenant des paramètres (e.g. /events/ID DE MON EVENT)
Il est possible de définir des paramètres dans une route :
{
path: '/events/:eventId',
name: 'EventDetails',
props: true,
component: EventDetails
}
{
path: '/events/:eventId',
name: 'EventDetails',
props: true,
component: EventDetails
}
Ces paramètres seront automatiquement mappés aux props du composant:
export default {
name: 'EventDetails',
props: {
eventId: String,
},
}
{
path: '/events/:eventId',
name: 'EventDetails',
props: true,
component: EventDetails
}
export default {
name: 'EventDetails',
props: {
eventId: String,
},
}
Il est toujours possible d'utiliser des router-links :
Détails de l'évènement {event.name}
ComposterDetailPage.vue qui se contente d'afficher un titre "Détail du composteur {{ id }}" puis réutilise le composant Composter
/composter-detail/:id associée à cette nouvelle pageNote: il est possible d'exécuter un changement de route en JS pur (tous les détails ici)
// literal string path
router.push('home')
// object
router.push({ path: 'home' })
// named route
router.push({ name: 'user', params: { userId: '123' } })
// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
Les SPA permettent généralement de réduire le trafic réseau puisque le code est téléchargé une seule fois. Mais il est possible que ce comportement ne soit pas optimal. Avez-vous un exemple ?
→ Si notre app a une page d'accueil simple visitée par 100k visiteurs par jours, et que le reste de l'application est reservée aux membres loggés (1k visite par jour), il semble peu judicieux que les 100k qui arrivent sur la page d'accueil téléchargent toute l'application.
→ le router vue permet de préciser qu'une ou plusieurs routes doivent faire l'objet d'une SPA dédiée
→ le router vue permet de préciser qu'une ou plusieurs routes doivent faire l'objet d'une SPA dédiée
{
path: "/",
name: "LightHome",
// route level code-splitting
// this generates a separate chunk (ligh-home.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "light-home" */ "../pages/LightHome.vue"),
}
C'est un usage avancé, mais prenez le réflexe de penser à faire de l'Eco-conception
C'est un usage avancé, mais prenez le réflexe de penser à faire de l'Eco-conception
Ce n'est pas le sujet du cours, mais je vous invite à vous renseigner sur l'Eco-Index (des plugins pour Chrome/Firefox permettent de le calculer facilement) et l'eco-conception en général (par exemple en regardant cette conférence de mes collègues lutins)
Le router vue permet des usages bien plus avancés (e.g. ajouter des conditions de gardes à certaines routes, définir des routes imbriquées...)
La documentation de Vue est vraiment très bien faite, n'hésitez pas à la consulter.
On est maintenant capable de
v-bind, v-if, v-on, v-forcomputed properties pour factoriser des calculsQu'est ce qu'il manque à notre application pour être utile ?
🌐 Aller chercher des vraies données depuis un serveur REST
⌚ Gérer l'asynchronicité (Promise)
✏ Comprendre le cycle de vue des composants Vue
Ce sera l'objectif de notre prochaine (et dernière) séance