Comprendre Vue.js : Nuxt en action
Lundi 26 novembre 2018 16:58
Dans le précédent article je vous ai présenté Nuxt. On a vu qu'il simplifie le développement d'une application Vue en gérant par exemple de façon automatisé le routage. Dans le présent article je vous propose de l'utiliser pour une petite application de recherches d'informations nutritives à partir d'un code-barre. Ce genre d'application se multiplie étant donné la sensibilisation croissante aux méfaits des additifs et à l'équilibre alimentaire. Il existe une base de donnée ouverte renseignée par les utilisateurs qui expose une API que nous allons utiliser. C'est d'ailleurs cette API qui est exploitée par toutes les applications qui existent actuellement.
Open Food Facts
Open Food Facts est une initiative citoyenne mondiale indépendante de l'industrie à laquelle tout un chacun est invité à participer. Elle récence actuellement 452688 produits et la base s'agrandit tous les jours. Pour chaque produit on peut obtenir une foule d'informations comme les ingrédients utilisés, le nutriscore, le fabricant...On crée le projet
On crée un projet Nuxt en mode SPA :npx create-nuxt-app produits
npx: installed 402 in 10.099s
> Generating Nuxt.js project in E:\laragon\www\vue-tuto\produits
? Project name produits
? Project description Tout savoir sur les produits
? Use a custom server framework none
? Use a custom UI framework vuetify
? Choose rendering mode Single Page App
? Use axios module yes
? Use eslint yes
? Use prettier no
? Author name bestmomo
? Choose a package manager npm
J'ai ajouté Vuetify, Axios et Eslint. On se retrouve avec cette architecture :
On n'a plus qu'à lancer :
npm run dev
On attend que tout se construise...
Ça se termine par quelque chose comme ça :
Et on se retrouve avec la même page d'accueil que lors du précédent article :
Le layout et la page d'accueil
On va commencer par changer le layout (layouts/default.vue) :<template>
<v-app dark>
<v-navigation-drawer
v-model="drawer"
clipped
fixed
app
>
<v-list>
<v-list-tile
to="/">
<v-list-tile-action>
<v-icon>find_in_page</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Rechercher</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile
href="https://fr.openfoodfacts.org"
target="_blank">
<v-list-tile-action>
<v-icon>help</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>Comprendre</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<v-toolbar
app
fixed
clipped-left>
<v-toolbar-side-icon
@click.stop="drawer = !drawer"/>
<v-toolbar-title>Open Food facts</v-toolbar-title>
</v-toolbar>
<v-content>
<v-container
fluid
fill-height>
<nuxt />
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
data: () => ({
drawer: null
})
}
</script>
On change ainsi la mise en page globale :
Le lien Comprendre emmène sur le site d'open Food facts.
On peut supprimer la page inspire :
Et on met ce code dans index.vue :
<template>
<v-layout
column
justify-center
align-center>
<v-flex
xs12
sm8
md6>
<div class="text-xs-center">
<img src="https://static.openfoodfacts.org/images/misc/openfoodfacts-logo-fr-178x150.png">
</div>
<v-alert
:value="alert"
type="error">
Aucun produit trouvé !
</v-alert>
<v-card>
<v-card-title
class="headline">
Bienvenue sur Open Food Facts !
</v-card-title>
<v-card-text>
<v-form @submit.prevent="submit">
<v-text-field
v-model="code"
label="Entrez le code barre et appuyez sur 'Entrée'"
type="number"
required
/>
</v-form>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</template>
<script>
export default {
data() {
return {
code: '',
alert: false
}
},
methods: {
submit() {
// Ici il faut traiter la soumission
}
}
}
</script>
On va chercher le logo sur le site d'Open Food Facts. On crée un formulaire avec juste une zone de saisie pour le code barre et on prépare une alerte pour le cas où aucun produit n'est trouvé.
On peut supprimer les composants des logos devenus inutiles :
Appel de l'API et Vuex
On va utiliser Axios pour aller chercher les informations du produit qui correspond au code barre entré. Sur le site on trouve ces informations pour l'API : Il est donc facile d'appeler cette API... Maintenant où va-t-on placer les données reçues ? On veut les rendre disponibles pour plusieurs pages, donc plusieurs composants, dans ce cas le plus indiqué est de passer par Vuex. La bonne nouvelle c'est que Nuxt installe automatiquement Vuex ! On a un dossier store déjà présent : On va créer un fichier index.js avec ce code :import Vuex from 'vuex'
const createStore = () => {
return new Vuex.Store({
state: {
data: {}
},
mutations: {
setData (state, data) {
state.data = data
}
}
})
}
export default createStore
Juste un mutateur setData qui attend les informations pour les mettre dans data.
On va compléter la vue index.vue pour appeler l'API et remplir le store :
<script>
import axios from 'axios'
export default {
data() {
return {
code: '',
alert: false
}
},
methods: {
submit() {
if(this.code != 0 && !isNaN(this.code)) {
axios.get(`https://fr.openfoodfacts.org/api/v0/produit/${this.code}.json`)
.then((res) => {
if(res.data.status) {
this.$store.commit('setData', res.data.product)
} else {
this.alert = true
}
})
}
}
}
}
</script>
On utilise Axios et au retour on vérifie la donnée status qui nous indique si un produit a été trouvé. Si ce n'est pas le cas on change la valeur de et l'alerte devient visible :
Si le produit existe alors le store est rempli :
La vue des détails
Maintenant qu'on a récupéré les informations il faut les afficher, on va créer une vue details.vue : Avec ce code :<template>
<v-layout>
<v-flex
xs12
sm6
offset-sm3>
<v-card>
<v-img :src="$store.state.data.image_url"/>
<v-card-title primary-title>
<div>
<div class="headline">{{ $store.state.data.product_name }}</div>
<span class="grey--text">{{ $store.state.data.generic_name }}</span>
</div>
</v-card-title>
<v-card-text class="mb-4">
<v-list>
<v-list-tile>
<v-list-tile-title><strong>Marque :</strong> {{ $store.state.data.brands }}</v-list-tile-title>
</v-list-tile>
<v-list-tile v-if="$store.state.data.serving_size">
<v-list-tile-title><strong>Quantité :</strong> {{ $store.state.data.serving_size }}</v-list-tile-title>
</v-list-tile>
<v-list-tile>
<v-list-tile-title><strong>Conditionnement :</strong> {{ $store.state.data.packaging_tags.join(', ') }}</v-list-tile-title>
</v-list-tile>
<v-list-tile>
<v-list-tile-title><strong>Magasins :</strong> {{ $store.state.data.stores }}</v-list-tile-title>
</v-list-tile>
<v-list-tile v-if="$store.state.data.manufacturing_places">
<v-list-tile-title><strong>Fabrication :</strong> {{ $store.state.data.manufacturing_places }}</v-list-tile-title>
</v-list-tile>
<v-list-tile v-if="$store.state.data.labels">
<v-list-tile-title>{{ $store.state.data.labels }}</v-list-tile-title>
</v-list-tile>
<v-list-tile>
<img
:src="nutriscore($store.state.data.nutrition_grades)"
width="120px"
class="pt-4">
</v-list-tile>
</v-list>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</template>
<script>
export default {
name: 'Details',
methods: {
nutriscore: function(value) {
return `https://static.openfoodfacts.org/images/misc/nutriscore-${value}.svg`
}
}
}
</script>
On sait que Nuxt va automatiquement créer une route /details. Donc dans la vue index.vue on appelle cette route :
if(res.data.status) {
this.$store.commit('setData', res.data.product)
this.$router.push('/details')
} else {
Et maintenant on obtient les détails du produit :
Les ingrédients
On ne va pas s'arrêter en si bon chemin et on va ajouter une vue pour afficher les ingrédients : Avec ce code :<template>
<v-layout>
<v-flex
xs12
sm6
offset-sm3>
<v-card>
<v-img
:src="$store.state.data.image_ingredients_url"/>
<v-card-title primary-title>
<div>
<div class="headline">{{ $store.state.data.product_name }}</div>
<span class="grey--text">{{ $store.state.data.generic_name }}</span>
</div>
</v-card-title>
<v-card-text>
<p><strong>Liste des ingrédients :</strong></p>
<p>{{ $store.state.data.ingredients_text_fr }}</p>
</v-card-text>
<v-card-actions>
<v-btn
flat
to="/details"
color="orange">Détails</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</template>
<script>
export default {
name: 'Components'
}
</script>
Et dans la vue details on ajoute un bouton pour accéder à cette nouvelle vue :
<v-card-actions>
<v-btn
flat
to="/components"
color="orange">Composants</v-btn>
</v-card-actions>
On a donc maintenant accès aux ingrédients des produits :
Conclusion
On voit ainsi qu'il est très facile de créer des vues avec des routes qui se créent automatiquement. D'autre part Vuex nous permet d'accéder aux données à partir de n'importe quel composant de l'application, ce qui est bien pratique.Par bestmomo
Nombre de commentaires : 1