Vue.js

/vju:/

 

@AurelienLoyer

Aurélien LOYER

       @AurelienLoyer

CTO Zenika Montréal

Vue.js - Plan

 

  • Les Composants
  • Les Directives
  • Les Filtres
  • HTTP
  • Routeur
  • Formulaire
  • VueX

Vue.js

 

- Librairie pour créer des composants

- Permet de créer une application "rapidement"

- Pas la prétention de concurrencer Angular et ReactJS

- Principaux éléments : Vues, Directives, Composants et Bindings

- Utilisation du Shadow DOM

npm install -g @vue/cli
// OR
yarn global add @vue/cli

// vue init webpack my-project
vue create my-project

cd my-project

npm install

npm run serve

npm run build

Vue.js - Interpolation

<div id="zenika">
  {{ message }}
</div>
let app = new Vue({
  el: '#zenika',
  data() {
    return {
        message: 'Hello Zenika!'
    }
  }
})

Vue.js - Bindings

<div id="zenika" v-bind:class="css">
  {{ message }}
</div>
let app = new Vue({
  el: '#zenika',
  data() {
    return {
      message: 'Hello Zenika!',
      css: 'rouge-zenika'
    }
  } 
})

Vue.js - Bindings

<div id="zenika" :class="css">
  {{ message }}
</div>
let app = new Vue({
  el: '#zenika',
  data() {
    return {
      message: 'Hello Zenika!',
      css: 'rouge-zenika'
    }
  } 
})

Vue.js - Events Handlers

<ul id="zenika">
   <button v-on:click="add">Add Aurélien</button>
</ul>
let app = new Vue({
  el: '#zenika',
  data: { consultants: [ ... ] },
  methods: {
    add(){
        this.consultants.push({name: 'Aurélien'})
    }
  }
})

Vue.js - Events Handlers

<ul id="zenika">
   <button @click="add('Aurélien')">Add Aurélien</button>
</ul>
let app = new Vue({
  el: '#zenika',
  data: { consultants: [ ... ] },
  methods: {
    add(name){
        this.consultants.push({name})
    }
  }
})

PW #1

Toute notre app dans la même Vue ? 

Les Composants

Vue.js - Global Components

<div id="zenika">   
    <ul>
       <li ...> ... </li>   
    </ul>
    <c-form></c-form>
</div>
Vue.component('c-form', {
   template: '<input /><button>Add</button>',
   data(){
    return {
        ...
    }
   }
})

let app = new Vue({
  el: '#zenika'
});

Vue.js - Global Components

Vue.js - Global Components

<div id="zenika">
    <ul>
       <li ...> ... </li>
    </ul>
    <c-form :value="'Arnaud'"></c-form>
</div>
Vue.component('c-form', {
   template: `
        {{ value }}
        <button>Add</button>'
   `,
   props: ['value']
})

let app = new Vue({ ... });

Vue.js - Global Components

<div id="zenika">
    <ul>
       <li ...> ... </li>
    </ul>
    <c-form :value="'Arnaud'"></c-form>
</div>
Vue.component('c-form', {
   template: `
        {{ value }}
        <button>Add</button>'
   `,
   props: {
        value: {
            type: String, 
            required: false,
            default: 'Manu'
        }
   }
})

Vue.js - Global Components

Vue.component('c-form', {
   template: `
        {{ value }}
        <button @click="click">Add</button>'
   `,
   props: ['value'],
   methods: { 
      click(){
          this.$emit('newconsultant', this.value)
      }
   }
});

Vue.js - Global Components

<div id="zenika">
    <ul>
       <li ...> ... </li>
    </ul>
    <c-form :value="'Arnaud'"
            @newconsultant="add"></c-form>
</div>
let app = new Vue({ 
    ...,
    methods: {
        add(consultant){
            this.consultants.push(consultant)
        }
    } 
});

Vue.js - local component

let cForm =  {
   template: `...`,
   props: ['value'],
   methods: { 
      click: ...
   }
})

let app = new Vue({ 
    ...,
    components: {
      'c-form': cForm  
    } 
});

Vue.js - Cycle de vie

.vue

Vue.js - Fichiers .vue

- Import via des modules ECMAScript 2015

- Meilleur découpage, testable facilement

- Tout le code au même endroit

- Intégration WebPack (hot reloading, préprocesseurs CSS, ...)

- CSS scopé

 

Vue.js - Fichiers .vue

<template>
    <c-form></c-form>
</template>

<script>
    import Form from './Form.vue'

    export default {
       props: ['value'],
       components: {
        'c-form': Form
       }
    }
</script> 
   
<style lang="css" scoped>...</style>

PW #2

Les Directives

Vue.js - Directives

<ul id="zenika">
    <li v-for="c in consultants" 
        v-if="c.name != 'Aurélien'">
      {{ c.name }}
   </li>
</ul>
let app = new Vue({
  el: '#zenika',
  data: {
    consultants: [ 
        {name: 'Manu'}, 
        {name: 'Aurélien'}
    ]
  }
})

v-for, v-if, v-else
v-model, v-once, v-bind, v-show, v-cloak, ...

Vue.js - Directives

<div id="zenika">
  <input type="text" v-required>  
</div>
Vue.directive('required', {
  inserted(el) {
    el.addEventListener('blur', () => {
    	if(!el.value) {
      	el.classList.add('has-error');
      } else {
      	el.classList.remove('has-error');
      }
    })
  }
})

PW #3

Les Filtres

  • Manipulation de la donnée avant affichage
  • Fonction de transformation locale ou globale
  • Utilisation du | l'exécuter

 

Filtre global

Vue.filter('reverse', value => {
  return value.split('').reverse().join('')
});

let app = new Vue({ 
    ...
});
<ul id="zenika">
      {{ c.name | reverse }}
</ul>

Filtre Local

let app = new Vue({ 
    ...,
    filters: {
        uppercase(value){
            return value.toUpperCase();
        }
    }
});
<ul id="zenika">
    {{ c.name | uppercase }}
</ul>

Computed Values

let app = new Vue({ 
    ...,
    computed: {
        sortedUsers(){
            return this.data.sort( ... );
        }
    }
});
<ul id="zenika">
   <ul>
         <li v-for="user in sortedUsers">
            {{name}}
        </li>
   </ul>
</ul>

PW #4

HTTP

  • Fin de vue-resource ...

  • Utilisation du module Axios
  • Module permettant d'exécuter des requêtes HTTP
  • Utilisation des Promise
  • Support des Intercepteurs
  • Possibilité de définir une configuration globale

axios - $http

import Vue from 'vue';
import axios from 'axios';

Vue.prototype.$http = axios;

axios - $http

import Vue from 'vue';
import axios from 'axios';

Vue.prototype.$http = axios;

axios.defaults.baseURL = '/api';
axios.defaults.headers
    .common['Authorization'] = 'token';

axios - $http

import Vue from 'vue';
import axios from 'axios';

Vue.prototype.$http = axios;

axios.defaults.baseURL = '/api';
axios.defaults.headers
    .common['Authorization'] = 'token';

axios.interceptors.request.use(config => {
    //Mise à jour de la requête
    return config;
});
axios.interceptors.response.use(response => {
    //Mise à jour de la réponse
    return response;
});

axios - $http

this.$http.get(url, [options])

this.$http.head(url, [options])

this.$http.delete(url, [options])

this.$http.jsonp(url, [options])

this.$http.post(url, [body], [options])

this.$http.put(url, [body], [options])

this.$http.patch(url, [body], [options])

axios - $http

let conferences = [];

this.$http.post('/devoxx', {day: 1})
    .then(response => {

        //response.status;

        conferences = response.data;

    }, response => {

        // error callback

    });

axios - $http

let app = new Vue({ 
    datas: {
        conferences: []
    },
    created(){
        this.$http.get('/devoxx')
            .then(response => {
                this.conferences = response.data;
            });
    } 
});

PW #5

Le Routeur

  • Configuration orientée composant
  • Utilisation des composants router-link et router-view
  • Récupération des informations courantes via l'objet $route
  • Redirection programmatique via l'objet $router
  • Support du lazy loading, des guards, des vues nommées et vues imbriquées

VueJS - Routeur

const Conferences = { template: '<div>Conférences Page</div>' }
const Conference = { template: '<div>Conférence Page</div>' }
const Inscription = { template: '<div>Inscription Page</div>' }

const routes = [
  { path: '/conferences', component: Conferences },
  { path: '/conference/:id', component: Conference },
  { path: '/inscription', component: Inscription }
]

const router = new VueRouter({
  routes 
})

const app = new Vue({
  el: '#app',
  router
})

VueJS - Routeur

<nav>
    <ul>
        <li>
          <router-link to="/conferences">Conférences</router-link>
        </li>
        <li>
          <router-link to="/inscription">Inscription</router-link>
        </li>
    </ul>
</nav>

<router-view></router-view>    

VueJS - Routeur

// Conference.vue - <script>

export default {
  data () {
    return {
      conference: null
    }
  },
  created () {
    this.getConference()
  },
  watch: {
    '$route': 'getConference'
  },
  methods: {
    getConference () {
      this.$http.get(`/conference/${this.$route.params.id}`)
        .then(data => this.conference = data.body);
    },
    goHome () {
        this.$router.push('/');    
    }
  }
}

PW #6

Les Formulaires

Devinez le nom de la directive pour interagir avec un <input / > ?

  • Utilisation de la directive v-model
  • Support tous les inputs HTML
  • Possibilité de définir des Modifiers
  • Pas de système de validation des données
  • 'Persistance' de la donnée lors du submit du formulaire

VueJS - Models

<form @submit="add">
   <input v-model="consultant" />
   <button type="submit">Add</button>
</form>
let app = new Vue({
  el: '#zenapp',
  data: { consultant: '', consultants: [ ... ] },
  methods: {
    add(){
        this.consultants.push({
            name: this.consultant
        });
        this.consultant = '';
    }
  }
})

VueJS - Models

<form @sumit="add">
   <input v-model.trim="consultant" /><!--.number-->
   <button type="submit">Add</button>
</form>
let app = new Vue({
  el: '#zenapp',
  data: { consultant: '', consultants: [ ... ] },
  methods: {
    add(){
        this.consultants.push({
            name: this.consultant
        });
        this.consultant = '';
    }
  }
})

VueJS - Validateurs

<form @sumit="add">
   <input v-model="password" name="password" 
            v-validate="'required'"/> 
   
   <span v-show="errors.has('password')" class="error">
        {{ errors.first('password') }}
   </span>
  
   <button type="submit">Add</button>
</form>
import Vue from 'vue';
import VeeValidate from 'vee-validate';

Vue.use(VeeValidate);

PW #7

Vuex

  • Centralisation de l'état de votre application et des mutations dans un store
  • Toutes mises à jours d'une donnée passera par un commit
  • Création d'un mapping entre une variable locale et une variable du store

VueX

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    agenda:[]
  },
  mutations: {
    addConference(state, conference) {
      state.agenda.push(conference);
    }
  }
});

new Vue({
  el: '#app',
  store,
});

VueX

<template>
    <div>
        Vous avez choisi {{ conferences.length}} 
        conferences

        <button @click="add">Ajoutez cette conference</button>
    </div>
</template>

<script>
module.exports {
   computed: {
      conferences() {
        return this.$store.state.agenda;
      }
   },
   methods: { 
      add(){
          this.$store.commit('addConference', 'VueJS');
      }
   }
}
</script>

VueX

VueX

PW #8

MERCI !

 

🙏

@AurelienLoyer

@T3kstiil3

Handson - VueJS

By Aurelien Loyer

Handson - VueJS

Depuis le temps que vous allez à des conférences, vous avez sûrement participé à des codelabs React et/ou Angular. Vous êtes même devenu peut-être un expert sur l'une de ces technos. C'est pour cela que nous avons décidé de ne pas choisir l'un de ces deux projets. Pendant ce codelab, nous avons choisi une toute autre librairie que nous sommes en train de tester pour des projets perso : VueJS. A travers ces 3 heures, nous allons aborder tous les concepts vous permettant de créer une application riche : composants, directives, mixins, routers, ... A la fin de ce codelab, vous allez pouvoir vous rendre compte que VueJS gagne le combat des frameworks/librairies JavaScript par sa simplicité et sa facilité de mise en oeuvre, tout en réutilisant certains concepts de ses deux concurrents.

  • 3,407