Commit c6281203 authored by Stephane Bouvry's avatar Stephane Bouvry
Browse files

Présentation VUEJS

parent 8aa651ac
Loading
Loading
Loading
Loading

vuejs.md

0 → 100644
+850 −0
Original line number Diff line number Diff line
% VUEJS
% Dev Note
% Novembre 2020

# Premiers pas


## Utilisation simple

Prise en main et découverte **de base** (pour tester rapidement) :


## Hello World

```html
<script src="../lib/vue.js"></script>
<div id="app"></div>
<script type="text/javascript">
new Vue({
  el: "#app",
  template: `<h1>Hello World</h1>`
});
</script>
```

Le template est dans **l'instance de Vue**

---

Idem, mais avec le template dans le DOM :

```html
<script src="../lib/vue.js"></script>
<div id="app">
  <h1>Hello World</h1>
</div>
<script type="text/javascript">
new Vue({
  el: "#app"
});
</script>
```

---

Dans les deux cas, ça fonctionne pour des vues simples...

---

## Data binding

Vue fonctionne avec un modèle **data** qui sera automatiquement **réactif** :
```html
<div id="app">
  <h1>Hello {{ who }} !!!</h1>
</div>
```
```js
var myApp = new Vue({
  el: "#app",
  data: {
    who: "All The World"
  }
});
```

Testez dans la **console** : `myApp.who = "Codeur"`

---

Pour utiliser une donnée dans un attribut, on utilise la **directive** `v-bind:attribute` :

```html
<div id="app">
  <h1 v-bind:title="who">Survolle moi</h1>
</div>
```

```js
new Vue({
  el: "#app",
  data: {
    who: "All The World"
  }
});
```

# Sous le capot

## render

Le rendu des vues repose sur la méthode `render` :

```html
<div id="app"></div>
```

```js
new Vue({
  el: "#app",
  data: {
    msg: "Hello World"
  },
  render(createElement){
    return createElement('h1', this.msg);
  }
});
```

---

Le rendu est basé une un *Virtual DOM* : Optimisation, rapidité

```js
var myApp = new Vue({
  el: "#app",
  data(){
    return {
      who: "Foo"
    }
  },
  render(createElement){
    return createElement('p',
      [ 'Hello ', createElement('strong', this.who), " !" ]
    );
  }
});
```

---

Les *templates* sont convertis en fonction `render(h)`, pour info, la classe **Vue** propose une méthode **compile** pour produire cette compilation :

```js
var template = "<h1>{{ variable }}</h1>";
console.log(Vue.compile(template));
```

---

En production / situation *rééle*, on utilise des fichiers **.vue** associés à des utilitaires **nodejs** pour obtenir du javascript compilé.


# Datas et méthodes

## data

Chaque instance dispose d'un modèle interne et *réactif* via la propriété `data` : 

```js
var myApp = new Vue({
  data(){
    return {
      foo: "Valeur FOO",
      bar: "Valeur BAR",
      liste: ["item A", "item B", "item C"]
    }
  }
});
```

---

La clef `data` se présente souvent sous la forme d'une méthode retournant un objet de donnée pour éviter les problèmes de pointeur (plusieurs instances) : 

```js
var myApp = new Vue({
  data(){
    return {
      /* Donnèes */
    }
  }
});
```

---

Les propriétés *doivent être initialisées* dans l'objet `data` pour garantir leur *réactivité*.

## methods

La clef `methods` permet d'ajouter des logiques personnalisées (`this` fait référence à l'instance).

```js
var myApp = new Vue({
  data(){
    return {
        valeur: "initiale"
    }
  },
  methods: {
    handlerRandom(){
      this.valeur = "Nouvelle valeur " + Math.random()
    }
  }
});
```

# Template

## Rendu textuel

Utilise la **syntaxe moustache** : 

```html
<div>
    <h1>{{ valeur }}</h1>
</div>
```

## Expression JS

Le contenu d'une *moustache* est une expression Javascript : 

```html
<div>
    <h1>Partie {{ nombre + 5 }}</h1>
    <p>Il y'a {{ totalPersonne }} 
        connectée{{ totalPersonne > 1 ? 's' : '' }}</p>
</div>
```

## Attributs dynamique

Utilise la directive `v-bind:attribut` ou `:attribut` : 

```html
<div>
    <h1 :title="valeur">{{ valeur }}</h1>
</div>
```

---

le contenu de l'attribut est une **expression Javascript** : 

```html
<div>
    <h1 :title="'Valeur vaut : ' + valeur">{{ valeur }}</h1>
</div>
```

## v-for : Array

Affichage des données type *forable* (Tableau, Object);

```js
var myApp = new Vue({
  data(){
    return {
        lettres: ["A","B","C"]
    }
  }
});
```

```html
<ul>
    <li v-for="lettre in lettres">{{ lettre }}</li>
</ul>
```

---

Liste d'objet :

```js
var myApp = new Vue({
  data(){
    return {
      languages: [
        { label: "Javascript" },
        { label: "PHP" },
        { label: "CSS" }
      ]
    }
  }
});
```

```html
<ul>
    <li v-for="l in languages">{{ l.label }}</li>
</ul>
```

## v-for : Object

Affichage des données type *forable* (Tableau, Object);

```js
var myApp = new Vue({
  data(){
    return {
      informations: {
        title: "Titre",
        description: "Description"
      }
    }
  }
});
```

```html
<ul>
    <li v-for="valeur in information">{{ valeur }}</li>
</ul>
```

## v-for : Clef

Affichage des clef : 

```js
var myApp = new Vue({
  data(){
    return {
      informations: {
        title: "Titre",
        description: "Description"
      }
    }
  }
});
```

```html
<ul>
    <li v-for="valeur,clef in informations">{{ clef }} : {{ valeur }}</li>
</ul>
```

## Conditions

Les **directives** `v-if="condition"`, `v-elseif="condition"` et `v-else` 

```html
<div v-if="message">
    <p>{{ message }}</p>
</div>
```

---

```html
<div v-if="error">
    <p>Erreur : {{ error }}</p>
</div>
<div v-else>
    <p>Tout fonctionne bien</p>
</div>
```

## Le cas V-SHOW

Même principe que pour `v-if`, mais utilise CSS pour cacher l'élément (pas de modification du DOM) : 

```html
<div v-show="message">
    <p>{{ message }}</p>
</div>
```

# Events

## DOM

On peut capter les événements natif du DOM avec la directive `v-on:EVENT` ou `@EVENT` :

```html
<button @click="nbrClick++">
    Clique : {{ nbrClick }}
</button>
```

## Event et méthodes simples

```html
<button @click="handlerClick">Demo</button>
```

```js
new Vue({
    // ...
    methods: {
        handlerClick(e){
            console.log(e, "déclenché !");
            alert("Click !")
        }   
    }
})
```


## Modifiers

Vue propose une liste de *modifiers* usuels.

```html
<a @click.prevent="nbrClick++" href="#">
    Clique : {{ nbrClick }}
</a>
```

---

 - `prevent` : Ajoute un `event.preventDefault`
 - `stop` : Ajoute un `event.stop`
 - `capture` : Capture les événements de passage
 - `self` : Ne capture que les événements de l'élément
 - `once` : n'autorise d'une fois l'événement
 
-- 

Les modifiers sont très utilisés pour la capture des événements claviers : 

```html
<input :keyup.enter="handlerSubmit" />
```

Voir la doc pour plus d'informations

# Propriétés calculées et surveillance

## Propriétés calculées : computed

```html
<h1> Casting : {{ totalArtistes }} artistes
<button @click="acteurs.push('José')">Ajouter</button>
```

```js
var v = new Vue({
  el: '#app',
  data: {
    acteurs: ["Nicolas", "Etienne", "Cricri"],
    actrices: ["Hélene", "Cathy", "Johanna", "Bénédicte"]
  },
  computed: {
    // a computed getter
    totalArtistes: function () {
      // `this` points to the vm instance
      return this.acteurs.length + 
            this.actrices.length;
    }
  }
})
```

---

Le recalcule des propriétés calculées est dépendants des données réactive. 

**Attention** : Les méthodes semblent donner le même résultat, mais elles sont réexécutées à chanque rendu.

## Surveillance : Watchers

Les **watchers** permettent d'ajouter des comportements lors de changement dans le modèle : 

```js
var v = new Vue({
  el: '#app',
  data: {
    valeur1: "foo",
    valeur2: "bar",
    nombreChangement: 0
  },
  watch: {
    valeur1: function ( val ) {
      console.log('Valeur 1 a pris pour valeur : ' + val);
      this.nombreChangement++;
    },
    valeur2: function ( val ) {
      console.log('Valeur 2 a pris pour valeur : ' + val);
      this.nombreChangement++;
    }
  }
})
```

## Getter / Setter

On peut également surcharger les affectations : 

```js
var v = new Vue({
  el: '#app',
  data: {
    firstName: "",
    lastName: ""
  },
  computed: {
    fullName: {
      // getter
      get: function () {
        return this.firstName + ' ' + this.lastName
      },
      // setter
      set: function (newValue) {
        var names = newValue.split(' ')
        this.firstName = names[0]
        this.lastName = names[names.length - 1]
      }
    }
  }
})
```

# Formulaires et V-MODEL

## input

La directive `v-model` concerne les éléments de formulaire et automatise le *binding* entre d'UI et le modèle : 

```html
<input type="text' v-model="fullname" />
<p>Fullname : {{ fullname }}</p>
```

## textarea

On est **obligé** d'utiliser `v-model` : 
```html
<textarea type="text' v-model="comment"></textarea>
<p>Commentaire : {{ comment }}</p>
```

## checkbox

Fonctionne avec un booleen : 
```html
<div :class="accepted ? 'accept' : 'notaccept'">
    Accepter les conditions ?
    <input type="checkbox" v-model="checked" />
</div>
```

```js
new Vue({
    // ...
    data(){
        return {
            accepted: false
        }
    }
})
```

---

ou une liste : 

```html
Présents : 
<label for="jack">JACK</label>
<input id="jack" type="checkbox" value="jack" v-model="presents" />
<label for="serge">SERGE</label>
<input id="serge" type="checkbox" value="serge" v-model="presents" />
<code>{{ presents }}</code>
```

```js
new Vue({
    // ...
    data(){
        return {
            presents: ["serge"]
        }
    }
})
```

## Radio

```html
Choississez le coupable : 
<label for="jack">JACK</label>
<input id="jack" type="radio" value="jack" v-model="coupable" />
<label for="serge">SERGE</label>
<input id="serge" type="radio" value="serge" v-model="coupable" />
<code>{{ coupable }}</code>
```

```js
new Vue({
    // ...
    data(){
        return {
            coupable: ""
        }
    }
})
```

## Select

```html
<select v-model="coupable">
    <option disabled value="">Choissisez le coupable</option>
    <option value="jack">JACK</option>
    <option value="serge">SERGE</option>
</select>
<code>Coupable : {{ coupable }}</code>
```

---

Voir la doc pour des utilisations avancées

# Classes CSS

## Via des objets

Sous la forme : 

```html
<section>
    <div :class="{ 'ClasseCSS': CONDITION }">
        S'affiche si CONDITION est TRUE
    </div>
</section>
```

## Computed

```html
<div :class="stylesCss">
    Exemple
</div>
```

```js
new Vue({
    // ...
    computed: {
        stylesCss(){
            return {
                'active': this.isActive,
                'has-error': this.errors.length > 0
            }       
        }   
    }
})
```

## Style

```html
<div v-:style="{ color: activeColor, fontSize: fontSize + 'px' }">
    Cracra mais fonctionne
</div>
```



# Composants

## Base

```js
Vue.component('compteur', {
    template: `<button @click="count++">COUNT {{ count }}</button>`,
    data(){ 
        return {
            count: 0
        }
    }
});
new Vue({ 
    // ...
});
```

```html
<div>
    <compteur></compteur>
</div>
```

---

Data **doit** être une fonction !

## Props

les **props** permettent de transmettre des donnèes aux composants : 

```js
Vue.component('compteur', {
    props: [ 'value' ],
    template: `<button @click="value++">COUNT {{ value }}</button>`
});
```

```html
<div>
    <compteur value="5"></compteur>
    <compteur value="8"></compteur>
    <compteur value="13"></compteur>
</div>
```

## Data de l'app via props

On utilise `v-bind` pour maintenir la réactivité si besoin : 

```js
Vue.component('titre', {
    props: [ 'value' ],
    template: `<h3>{{ value }}</h3>`
});
new Vue({
    data: {
        titre1: "Foo",
        titre2: "Bar",
        titre3: "Foo-Bar",
    }
})
```

```html
<div>
    <titre :value="titre1"></titre>
    <titre :value="titre2"></titre>
    <titre :value="titre3"></titre>
    <input type="text" v-model="titre1" />
    <input type="text" v-model="titre2" />
    <input type="text" v-model="titre3" />
</div>
```

--- 

Attention, pour modifier data dans ce cas, il faudra avoir recourts aux événements !

```js
// NE FONCTIONNE PAS !!!!
Vue.component('titre', {
    props: [ 'value' ],
    template: `<h3 @click="value = 'default'">{{ value }}</h3>`
});
// ...
```

## Events

```js
// Le composant émet un évenement
Vue.component('titre', {
    props: [ 'value' ],
    template: `<h3 @click="$emit('reset', 'default value')">{{ value }}</h3>`
});
// ...
```

```html
<div>
    <titre :value="titre1" @reset="titre1 = $event"></titre>
    <titre :value="titre2" @reset="titre2 = $event"></titre>
    <titre :value="titre3" @reset="titre3 = $event"></titre>
    <input type="text" v-model="titre1" />
    <input type="text" v-model="titre2" />
    <input type="text" v-model="titre3" />
</div>
```

--- 

La reception et le traitement d'un événement passe plutôt par une méthode : 

```html
<div>
    <titre :value="titre1" @reset="handlerReset1"></titre>
    <!-- etc... -->
    <input type="text" v-model="titre1" />
    <!-- etc... -->
</div>
```

```js
new Vue({
    data: {
        titre1: "Foo"
    },
    methods: {
        handlerResetA(valeur){
            console.log("Reçu", arguments);
            this.titre1 = valeur;
        }   
    }   
})
```

-- 

On peut envoyer plusieurs données : 

```js
// Le composant émet un évenement
Vue.component('titre', {
    props: [ 'value' ],
    template: `<h3 @click="$emit('reset', 'valeur 1', 'valeur 2')">{{ value }}</h3>`
});
// ...
```

il y'aura plusieurs paramètres dans la fonction handler : 


```js
handlerResetA(valeur1, valeur2){
    console.log("Reçu", arguments);
    this.titre1 = valeur1 + valeur2;
}
```



# Lifesycle Hooks

## created

Lorsque l'instance est créée (mais pas encore présente dans le DOM).

```js
new Vue({ 
    /* code */
    created(){
        console.log('Instance créée');
    }
});
```

## mounted

Lorque l'instance est **montée** dans le DOM.

```js
new Vue({ 
    /* code */
    mounted(){
        console.log('Instance créée');
    }
});
```

## Lifecycle

Pour d'information sur la documentation officielle : https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram