Déclarations
Les composants à intégrer
Le but du router étant de charger des composants au sein de l'application
en fonction de l'URL visée dans la barre d'adresse du navigateur,
il faut dans un premier temps créer ces composants.
NB : les composants chargés sont des composants Vue "classiques" tels que nous les avons créés dans les
parties précédentes de ce cours.
Nous allons ici prendre pour exemple 2 composants très simples nommés Blue.vue
et Red.vue
chargés d'afficher chacun un carré de couleur.
Pour simplifier l'exemple, le code de ces 2 composants est ici très similaire...
Blue.vue
<template>
<div id="blue-comp" class="square">
Blue
</div>
</template>
<script>
export default {
name: "Blue"
}
</script>
<style scoped>
@import "square.css";
#blue-comp{
background: lightskyblue;
}
</style>
Red.vue
<template>
<div id="red-comp" class="square">
Red
</div>
</template>
<script>
export default {
name: "Red"
}
</script>
<style scoped>
@import "square.css";
#red-comp{
background: lightpink;
}
</style>
square.css
.square{
width: 300px;
height: 300px;
margin: auto;
border: 1px solid black;
background: lightskyblue;
display: flex;
justify-content: center;
align-items: center;
font-size: 2em;
}
Importation, instanciation et configuration du router
L'étape suivante consiste à importer, instancier et configurer le router dans le script
de l'application.
Le script de App.vue
<script>
// importation des composants qui seront intégrés dynamiquement
import Blue from "@/components/Blue";
import Red from "@/components/Red";
// importation des packages pour faire fonctionner VueRouter
import Vue from 'vue' ;
import VueRouter from 'vue-router' ;
// DÉCLARATION DES ROUTES (un mapping URL -> composant à charger)
const routes = [
{ path: '/blue', component: Blue },
{ path: '/red', component: Red },
]
// instanciation du router
const router = new VueRouter({
routes // short for `routes: routes`
})
Vue.use(VueRouter) ;
export default {
name: 'App',
router // déclaration du router dans l'application
}
</script>
Insertion dans le template : router-view
Il ne reste plus qu'à indiquer l'endroit où seront chargés les composants et éventuellement mettre des liens
qui permettent de passer de l'un à l'autre.
On utilise la balise router-view
pour indiquer où seront chargés les composants:
cette balise sera remplacée par le composant chargé par le router en fonction de l'URL donnée au navigateur.
Le template de App.vue
<template>
<div id="app">
<h1>Router Application</h1>
<router-view></router-view>
</div>
</template>
Si on éxécute l'application comme nous l'avons fait jusqu'à présent (npm run serve
),
l'adresse http://localhost:8080/#/ affiche simplement le titre "Router Application".
En ajoutant une des routes
définies dans le script
(ex. http://localhost:8080/#/blue), le composant mappé sur cette
URL est chargé dynamiquement à l'endroit du router-view
.
Ajout de liens : router-link
On peut utiliser la balise router-link
pour créer des liens aisément
compréhensibles par le router : ces balises utilisent les routes
qui ont été définies
dans la partie script
de l'application.
Le template de App.vue (avec des liens)
<template>
<div id="app">
<h1>Router Application</h1>
<nav>
<router-link to="/blue">Blue</router-link>
<router-link to="/red">Red</router-link>
</nav>
<router-view></router-view>
</div>
</template>
L'exemple au complet
Voici le code complet de App.vue
, et le résultat obtenu :
App.vue
<template>
<div id="app">
<h1>Router Application</h1>
<nav>
<router-link to="/blue">Blue</router-link>
<router-link to="/red">Red</router-link>
</nav>
<router-view></router-view>
</div>
</template>
<script>
// importation des composants qui seront intégrés dynamiquement
import Blue from "@/components/Blue";
import Red from "@/components/Red";
// importation des packages pour faire fonctionner VueRouter
import Vue from 'vue' ;
import VueRouter from 'vue-router' ;
// DÉCLARATION DES ROUTES (un mapping URL -> composant à charger)
const routes = [
{ path: '/blue', component: Blue },
{ path: '/red', component: Red },
]
// instanciation du router
const router = new VueRouter({
routes // short for `routes: routes`
})
Vue.use(VueRouter) ;
export default {
name: 'App',
router // déclaration du router dans l'application
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
nav{
margin: 20px 0;
padding: 5px;
background: lightgray;
}
nav *{
margin: 20px 5px;
}
</style>
Résultat.
(Vous verrez mieux l'effet des routes dans la barre d'adresse en cliquant
ici)
NB: Nous ne le traiterons pas ici, mais dans la
documentation officielle,
vous pourrez constater qu'il est
aussi possible de définir des routes imbriquées (routage dans un sous-composant).
Segments Dynamiques
Grâce aux segments dynamiques, VueRouter permet d'utiliser une partie d'URL pour envoyer des
informations aux composants.
Prenons l'exemple d'un nouveau composant Square.vue
qui ressemble fortement à
Blue.vue
et Red.vue
, à la différence près que la couleur qu'il affiche n'est
pas prédéfinie (il est donc plus générique).
On décide ici que la couleur sera donnée dans l'URL par un segment placé après la route du composant.
-
La route du composant sera nommée
/square
.
-
Le paramètre donnant la couleur sera le code couleur CSS à afficher (ex.
/yellow
).
L'URL pour afficher le composant Square.vue
avec la couleur yellow
sera donc:
http://localhost:8080/#/square/yellow.
Ajout de route paramétrée
On va donc ajouter une route avec un segment dynamique vers le composant Square :
Dans le script de App.vue
...
import Square from "@/components/Square"
...
const routes = [
...
{ path: '/square/:color', component: Square},
]
NB: on suppose ici que Square.vue
a déjà été créé -> cf. le code ci-après...
Le signe :
indique où démarre le segment dynamique qui servira de paramètre
dans la route
qui mène au composant Square
.
Dans notre exemple, ce paramètre est donc nommé color
, et il sera remplacé par la chaine
qui suit la route /square/
.
En d'autres termes, dans http://localhost:8080/#/square/yellow,
le paramètre color
aura pour valeur yellow
.
Ajout de liens paramétrés
Puisque cette route contient un segment dynamique, on peut l'utiliser avec différentes valeurs de
paramètre. Nous allons donc ajouter 2 router-link
qui mènent vers le composant
Square.vue
, en la paramétrant avec les couleurs yellow
et green
.
Dans le template de App.vue
...
<router-link to="/square/yellow">Yellow</router-link>
<router-link to="/square/green">Green</router-link>
...
Paramètres dans le sous-composant : l'objet $route
Bien entendu, pour que tout cela fonctionne, il faut avoir créé le (sous-)composant Square.vue
en
faisant en sorte qu'il configure sa couleur avec le paramètre color
indiqué dans l'URL.
L'utilisation d'un VueRouter crée un objet $route
accessible dans toute l'application
(y compris dans les sous-composants), et qui permet d'accéder aux parties de l'URL.
Pour ce qui nous intéresse ici, $route
possède un attribut params
qui contient
lui-même les paramètres provenant d'un segment dynamique.
On pourra donc récupérer la valeur du paramètre color
avec
this.$route.params.color
.
Le code du composant Square.vue
est donc le suivant :
Square.vue
<template>
<div id="square-comp" class="square" :style="{ background: color}">
Square : {{ color }}
</div>
</template>
<script>
export default {
name: "Square",
data(){return{
color: this.$route.params.color // récupération du paramètre
}},
watch: {
'$route' (to, from){ // il faut mettre un watcher au cas où le paramètre change...
console.log(from)
this.color = to.params.color
}
}
}
</script>
<style scoped>
@import "square.css";
</style>
Vous aurez remarqué qu'on a aussi ajouté un watch
qui permet de "surveiller" l'objet
$route
et de réagir quand il change.
Ceci vient du fait que si l'application passe de http://localhost:8080/#/square/yellow à
http://localhost:8080/#/square/green (par exemple en cliquant sur un lien, puis sur l'autre),
le composant visé est 2 fois le même (Square.vue
). Par souci d'efficacité, Vue ne le
recharge pas, les data
ne sont donc pas re-calculées, et part conséquent,
la valeur de l'attribut this.color
reste la même -> la couleur du composant ne change pas.
NB: ne pas confondre l'attribut this.color
avec le paramètre
this.$route.params.color
!
Le watch
sur $route
permet de savoir que, même si le composant visé n'a pas changé
(et n'a donc pas été rechargé), l'URL a quand à elle subi une modification (ici, une nouvelle valeur pour
le paramètre this.$route.params.color
, qui doit être répercutée sur l'attribut
this.color
).
L'exemple au complet
App.vue
<template>
<div id="app">
<h1>Router Application</h1>
<nav>
<router-link to="/blue">Blue</router-link>
<router-link to="/red">Red</router-link>
<router-link to="/square/yellow">Yellow</router-link>
<router-link to="/square/green">Green</router-link>
</nav>
<router-view></router-view>
</div>
</template>
<script>
import Vue from 'vue' ;
import VueRouter from 'vue-router' ;
import Blue from "@/components/Blue";
import Red from "@/components/Red";
import Square from "@/components/Square";
const routes = [
{ path: '/blue', component: Blue },
{ path: '/red', component: Red },
{ path: '/square/:color', component: Square},
]
const router = new VueRouter({
routes // short for `routes: routes`
})
Vue.use(VueRouter) ;
export default {
name: 'App',
router,
}
</script>
<style>
...
</style>
Résultat.
(Vous verrez mieux l'effet des routes dans la barre d'adresse en cliquant
ici)
Les paramètres en tant que props
Il est aussi possible de modifier légèrement le code de l'application et du sous-composant pour faire
en sorte que, au lieu d'utiliser this.$route.params
, les paramètres soient envoyés
en tant que propriétés (props
).
Pour ce faire, il suffit de changer la route déclarée dans App.vue
comme suit :
Dans le script de App.vue
...
{ path: '/square/:color', component: Square, props: true},
...
Et la nouvelle version de Square.vue
, qui n'utilise plus $route
, et n'a plus
besoin de watch
puisque, comme vous le savez ;), les props
sont automatiquement
mises à jour dans les composants qui les utilisent.
Square.vue avec props
<template>
<div id="square-comp" class="square" :style="{ background: color}">
Props : {{ color }}
</div>
</template>
<script>
export default {
name: "Square",
props:{
color: String
}
}
</script>
<style scoped>
@import "square.css";
</style>
Il est possible de faire plus de choses avec les props
(et les segments dynamiques en général).
Pour plus d'infos c'est
ici.