Développement d'applications mobiles

Partie 2 - Vue.js et Progressive Webapps

Cours 1 - Introduction à Vue.js



Alex morel
Code Lutin

Avant de commencer

    Le but du module n'est pas:
  • d'apprendre les frameworks webs à la mode (iOnic...)
  • d'apprendre les fonctionnalités avancées de Vue (VueX, composition API...)
  • de vous affirmer "Expert Web" sur LinkedIn

Avant de commencer

    Le but du module c'est de
  • comprendre les problématiques du développement de webapps
  • maitriser des concepts et technos permettant d'y répondre
  • comprendre ce qu'est Vue, pourquoi ça existe, et ses principaux mécanismes
  • s'amuser avec le dev Web

Avant de commencer

    Je ne connais pas votre niveau en langages/outillage Web.

    On posera donc les principes suivants :
    - JS pur (pas de Typescript)
    - CSS pur (pas de scss/less/sass)
    - Build simple (pas webpack/eslint/prettier)

    POSEZ DES QUESTIONS, INTERVENEZ !

Plan du cours

Cours 1: introduction à Vue.js

Cours 2: Style (Bulma & class-binding)

Cours 3: Client-side routing

Cours 4: Rest, promises, ouverture

Notre fil rouge : CompostMap

Application pour visualiser les composteurs sur l'agglo nantaise

1 - Créer et lancer une App

Installer Vue cli (Command Line Interface)

npm install -g @vue/cli

Vue CLI offre des commandes pour facilement créer des projets Vue et les maintenir

Créer une application Vue

vue create compostmap

Lancer l'application Vue


						cd compostmap
						npm run serve
						

L'application est disponible sur http://localhost:8080/ (ou un autre port si occupé)

Pour spécifier un port particulier, modifiez la tâche "serve" dans le package.json ou

npm run serve -- --port 8072


commit : Code generated by 'vue create compostmap'

Structure d'une application Vue


  • public/index.htmlhtml contenant la div #app
  • src/App.vue composant principal App
  • src/main.js injecte App dans #app
  • src/assets/ dossier images,fichiers
  • src/components/ sous-composants

Structure d'une application Vue

  • public/index.htmlhtml contenant la div #app
<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>

Structure d'une application Vue

  • src/App.vue composant principal App
1 Composant = Un template HTML + du code + du style







Structure d'une application Vue

  • src/main.js injecte le composant App dans #app
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')				
					

Structure d'une application Vue


  • public/index.htmlhtml contenant la div #app
  • src/App.vue composant principal App
  • src/main.js injecte App dans #app
  • src/assets/ dossier images,fichiers
  • src/components/ sous-composants

Exercice 1: créer votre première App Vue

  • Créez et lancez une nouvelle application Vue "compostmap"
  • Dans le template HTML de votre composant App.vue, changez la valeur de msg
  • Rafraîchissez la page. Que constatez-vous ?

commit : Code generated by 'vue create compostmap'

2 - La réactivité dans

Les props et les data

Dans l'exemple précédent, msg est une props du composant HelloWorld.


Une prop peut être affichée avec la syntaxe {{nomDeMaProp}}

Les props et les data

Prop → variable passée par le parent (readonly)
Data → variable interne au composant (modifiable)


Une data peut être affichée avec la syntaxe {{nomDeMaProp}}

Les props

Vue.js écoute les props et les data : dès que leurs valeurs changent, les templates qui les référencent sont ré-évalués et la page est rafraîchie :

commit : 'Props demo'

Un peu de vocabulaire

  • Un composant Vue contient 3 parties :
    - le template (HTML) du composant
    - le script du composant (déclare les props, datas, methods...)
    - le style (CSS) du composant (optionnel)
  • Le moteur de rendu de Vue utilise ces 3 parties pour afficher et rafaîchir la page (le contenu du navigateur)
  • La page est aussi appelée DOM

On reviendra sur la notion de DOM plus tard, pour l'instant quand je parle de "DOM" dites-vous "la page affichée à l'utilisateur"

Exercice 2: définir et modifier des datas

  • Videz le template HTML de HelloWorld.vue
  • Définissez deux nouvelles data "title" et "subtitle" de type string dans votre composant HelloWorld
  • Affichez title dans un h1 et subtitle en-dessous
  • Copiez-collez ce bouton qui permet de modifier les valeurs des props msg et subtitle
    <button v-on:click="title += '$';subtitle += '€';"> Modifier</button>

commit : 'Exercice 2'
Template HTML

Bienvenue sur mon app {{ title }}

2. A besoin de la valeur de title pour créer la page
4. Page (DOM) créée
Navigateur
1. Veut afficher la page

Bienvenue sur Compostmap

Composant
data {
	title: "Compostmap"
}
3. Retourne la valeur initiale de title
Template HTML

Bienvenue sur mon app {{ title }}

Navigateur

Bienvenue sur Compostmap

Modified from data

Composant
data {
	title: "Modified from data"
}
Binding js → DOM :
si je modifie programmativement title
c'est propagé jusqu'à la page
Template HTML

Bienvenue sur mon app {{ title }}

Navigateur

Composant
data {
	title: "Modified from data"
}
Template HTML

Bienvenue sur mon app {{ title }}

Navigateur


Binding DOM → js :
si je modifie title via la page (e.g. input texte)
c'est propagé jusqu'au Composant
Composant
data {
	title: "Modified from data"
}
Template HTML

Bienvenue sur mon app {{ title }}

Navigateur


Binding DOM → js :
si je modifie title via la page (e.g. input texte)
c'est propagé jusqu'au Composant
Composant
data {
	title: "Modified from DOM"
}
Ce qu'il faut retenir pour l'instant
  • Les templates référencent des expressions (props et/ou datas)
  • Quand une prop/data est modifiée depuis le js, Vue met à jour la page (binding js → DOM)
  • Quand une prop/data est modifiée depuis la page, Vue met à jour sa valeur dans le composant (binding DOM → js)
  • On parle de binding bi-directionnel ("two-way binding")
  • Vue est un framework dit réactif ("reactive")
  • Connaissez-vous d'autres frameworks réactifs (reposant sur un binding bi-directionnel) ?
  • Angular

Le Reactivity System de Vue est complexe et intéressant à étudier (création d'un DOM virtuel, algorithmes de différenciations... ) mais pour l'heure cette notion de binding bi-directionnel nous suffira.

3- Le binding dans Vue

Créons un composant en charge d'afficher un composteur



→ Comment associer la data 'image' avec le src de l'img ?

→ Comment associer la data 'image' avec le src de l'img ?

→ Grâce à la directive v-bind



→ Grâce à la directive v-bind


commit : Bind example: image src

v-bind créé un lien entre :
-un attribut (ici l'attribut "src" de l'élément img)
- une expression (ici la data "image")

grâce au principe de réactivité (binding bi-directionnel) de Vue,
- si l'expression (ici la data 'image') change de valeur,
- Vue va détecter et propager ce changement
- l'attribut src sera mis à jour avec la nouvelle valeur de l'expression

commit : Bind example: image src

Exercice 3: binding de liens

  • Clonez le repository de notre application
  • Vérifiez que vous êtes sur le commit "Bind example: image src"
  • Lancer la commande npm install puis npm run serve
  • Autour de l'adresse, ajoutez un lien (balise 'a' avec un attribut href) vers le site de votre choix
  • Créez une nouvelle data 'url'
  • Utilisez v-bind pour binder l'attribut href avec la data 'url'
  • Modifiez la data 'url', le lien doit être rafraichi

Pour résumer avant de poursuivre

Le binding bi-directionnel de Vue, permet, quand les data changent :

  • de réévaluer les expressions concernées dans le template
    Bienvenue sur  {{ title }}
  • de réévaluer les attributs bindés concernés

Au passage

Les développeurs sont des faignants (ce n'est pas nouveau), aussi trouverez-vous une syntaxe alternative à v-bind :

est strictement identique à

Utilisez celle qui vous parle le plus

4. les directives v-if,
v-for et v-on

Une besoin courant est d'effectuer ou non le rendering d'éléments du template en fonction d'une condition.
Par exemple: si l'adresse contient le texte 'Nantes', afficher un message dédié

C'est l'objectif de la directive v-if

C'est l'objectif de la directive v-if:
conditionner le rendering d'un élément à la valeur d'une expression


commit : v-if example

On peut utiliser v-else pour effectuer un rendering alternatif


On peut utiliser v-else-if pour enchaîner les if puis finir par un v-else


Exercice 4: rendu conditionnel

  • Ajoutez une data 'isOpen' (booléen)
  • Afficher un paragraphe avec le texte 'Ouvert' si isOpen est vrai
  • Afficher un paragraphe avec le texte 'Fermé' si isOpen est faux

Imaginons que chaque compost dispose d'une liste de responsables :

data() {
	return {
		responsables: [
			{
				first_name: "Alex",
				last_name: "Morel",
			},
			{
				first_name: "Amandine",
				last_name: "Lagarde",
			},
			{
				first_name: "Pascal",
				last_name: "André",
			},
		],
	}
}

Comment effectuer le rendu de cette liste dans notre template?

Essayons l'approche naïve: utilisons {{ responsables }} comme on l'aurait fait pour une chaîne de caractères ou un nombre



commit : String array: naive approche

Ce que l'on veut faire: créer un élément dans le DOM pour chaque élément de notre collection

C'est l'utilité de la directive v-for

- {{ responsable.first_name }} {{ responsable.last_name }}

v-for attend une collection à afficher et une key(clé)

v-for attend une collection à afficher et une key(clé)

- {{ responsable.first_name }} {{ responsable.last_name }}

La key est utilisé par le mécanisme de réactivité pour identifier de manière unique chaque élément du DOM ainsi créé

→ Permet d'optimiser les performances du refresh quand la collection change (on ne change dans le DOM que ce qui a bougé dans la data)

→ Cette key est également utilisée par Vue dans d'autres contextes (animations...)


commit : Handling arrays - v-for directive

Plutôt qu'afficher chaque élément dans un <p>, quel balise html pourrait-on utiliser ?

<ul> et itérer sur chaque <li>

Exercice 5: affichage d'une collection

  • Ajoutez aux data 'openingSchedules', un tableau d'horaire d'ouvertures, chaque horaire disposant de 3 attributs 'day', 'opening_hour', 'closing_hour'
  • Exemple d'horaire valide:
    { day: 'Lundi', opening_hour: 9, closing_hour: 12}
  • Faire en sorte d'obtenir l'affichage suivant :

Grace à v-bind, v-if et v-for, nous sommes maintenant capable d'effectuer le rendu de nos data/props sur la page.

On souhaiterait maintenant pouvoir intercepter les Event html pour définir de la logique sur les interactions utilisateurs.
Avez-vous des exemples d'events html ?

on-click, on-mouse-over, oncopy, oninput... liste complète

On veut donc écouter et réagir aux évènements html (onClick, onMouseOver, OnInput...)

C'est l'utilité de la directive v-on

v-on prend en paramètres un évènement (click, mouseover, input...) et du code à exécuter

v-on prend en paramètres un évènement (click, mouseover, input...) et du code à exécuter


commit : V-on : inline example

Il est bien sûr possible d'appeler une méthode du composant avec la syntaxe suivante :


commit : V-on : method example

Exercice 6: intercepter le clic et la souris

  • Ajoutez un bouton qui, au clic, ajoute un jour d'ouverture random à openingSchedules
  • Faire en sorte que quand l'utilisateur passe la souris sur l'image, le dernier openingSchedule soit supprimé
  • Ajouter une data focusedDay de type string et l'afficher dans le template
  • Faire en sorte que lorsque l'utilisateur passe la souris sur un openingSchedule, focusedDay soit modifié en fonction

Au passage

Les développeurs sont des faignants (édition 2), aussi trouverez-vous une syntaxe alternative à v-on :

est strictement identique à

Utilisez celle qui vous parle le plus

Point d'avancement

On est maintenant capable de

  • Créer une application vue avec Vue CLI
  • Définir des props/datas dans un composant
  • Savoir que la réactivité de VueJS est bi-directionnelle
  • D'afficher une expression {{ maProp }}
  • De binder un attribut v-bind:href="maProp" ou :href="maProp"
  • D'effectuer du rendu conditionnel avec v-if,v-elseif et v-else
  • De rendre des collections v-for="e in array" v-bind:key="e.id">
  • D'intercepter des events v-on:click="method" ou @click="method"

Point d'avancement

On est maintenant capable de

  • Créer une application vue avec Vue CLI
  • Définir des props/datas dans un composant
  • Savoir que la réactivité de VueJS est bi-directionnelle
  • D'afficher une expression {{ maProp }}
  • De binder un attribut v-bind:href="maProp" ou :href="maProp"
  • D'effectuer du rendu conditionnel avec v-if,v-elseif et v-else
  • De rendre des collections v-for="e in array" v-bind:key="e.id">
  • D'intercepter des events v-on:click="method" ou @click="method"

Ce qui nous manque

Qu'est ce qu'il manque à notre application pour être montrable ?

😎 Du style (parce que là c'est affreux)

⌛ Un peu de pratique (créer nos propres composants)

☰ Un menu et une structure en différentes pages

Ce sera l'objectif du prochain cours


D'ici le prochain cours

- Entraînez-vous

- Harcelez-moi (par mail et/ou sur discoord)



Alex morel
Code Lutin
g