Vue.js de A à Z

Vue.js de A à Z

Emmet

! : Créer un squelette html

Nom des composants en spinal-case

Installation du serveur

npm init -y
npm install lite-server 

Ouvrir :

package.json

Chercher :

"test": "echo \"Error: no test specified\" && exit 1"

Remplacer par :

"test": "echo \"Error: no test specified\" && exit 1", 
"start": "lite-server"

npm start 

http://localhost:3000

Syntaxe moustache / Interpolation

{{ donnee }}

Squelette vue.js de base

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue JS Playground</title>

</head>

<body>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>

    <div id="mon-app">
            <h1>Vue JS Cours</h1>
    </div>

    <script>
            new Vue ({
            el : '#mon-app'
        })
    </script>
</body>
</html>

Donnée

<div id="mon-app">
    {{ txt }}
</div>

<script>
    new Vue ({
        el : '#mon-app',
        data: {
            txt: 'Hello World'
        }
    })
</script>

Méthodes

<div id="mon-app">
    {{ presentation() }}
</div>

<script>
    new Vue ({
        el : '#mon-app',
        data: {
            txt: 'Hello World'
        },
        methods: {
            presentation: function () {
                return 'Bonjour, je suis Sam'
            }
        }
    })
</script>

this

<div id="mon-app">
    {{ presentation() }}
</div>

<script>
    new Vue ({
        el : '#mon-app',
        data: {
            txt: 'Hello World'
        },
        methods: {
            presentation: function () {
                return this.txt;
            }
        }
    })
</script>

Data-binding

<div id="mon-app">
    <a v-bind:href="url">test</a><br>

    <a :href="url">test</a><br

    <img v-bind:src="url">
</div>

 <script>
    new Vue ({
        el : '#mon-app',
        data: {
            url: 'http://test.fr'
        },
    })
</script>

<img v-bind:src="url"> 

Raccourci : 

<img :src="url">

Directive "v-on"

Appel une méthode lors d'un event

<div id="mon-app">
   <button v-on:click="augmente">Augmente</button>
   {{ compteur }}
</div>

 <script>
    new Vue ({
        el : '#mon-app',
        data: {
            compteur: 0,
        },
        methods: {
            augmente : function () {
                this.compteur++;
            }
        }
    })
</script>

<button v-on:click="augmente">Augmente</button> 

Raccourci : 

<button @click="augmente">Augmente</button>

Event Modifier Directive v-once

Exécute 1 fois :

 <button v-on:click.once="augmente">Augmente</button>

Stop la propagation :

<button v-on:click.stop="augmente">Augmente</button> 

Stop le comportement par défaut :

<form v-on:submit.prevent="onSubmit"> 

Event Modifier Directive v-once

<div v-once>{{ nombre }}</div> // n'augmente pas
<div >{{ nombre }}</div>

<button v-on:click="augmente">Augmente</button>

Key Modifier

Lance la fonction quand appuyé sur [Entrée]

<input type="text" v-on:keyup.enter="inputFunc">

V-model lier à un input

Two-ways data binding

<body>
    <div id="mon-app">
        <input type="text" v-model="valeur">
        {{ valeur }}
    </div>
</body>

 <script>
    new Vue ({
        el : '#mon-app',
        data: {
            valeur : "",
        },            
    })
</script>

V-model lier à un select

Two-ways data binding

        <div id="mon-app">
        {{ selection }}

        <select v-model="selection">
            <option>Paris</option>
            <option>Londre</option>
        </select>
        </div>

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            selection : "",
        },            
    })
</script>

V-model lier à un textarea

        <div id="mon-app">
        <div style="white-space: pre-line">
        {{ multi }}
        </div>
        <textarea v-model="multi" cols="40" rows="7"></textarea>
        </div>

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            multi : "",
        },            
    })
</script>

Lier un vmodel et un v-bind

    <div id="mon-app">
        <input type="text" v-model="tex1" v-on:keyup="recopie()">
        <input type="text" v-bind="tex2">
    </div>

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            tex1 : "",
            tex2 : "",
        },  
        methods: {
            recopie: function () {
                this.text2 = this.text1.toUpperCase();
            }
        }          
    })
</script>

v-model et Checkbox

    <div id="mon-app">
        <input type="checkbox" value="html" v-model="cases">html
       <input type="checkbox" value="css" v-model="cases">css
    </div>
    {{ cases }}

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            cases : [],
        },            
    })
</script>    

v-model et radiobutton

    <div id="mon-app">
        <input type="radio" value="html" v-model="cases">html
       <input type="radio" value="css" v-model="cases">css
    </div>
    {{ cases }}

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            cases : "",
        },            
    })
</script>       

Opérateur ternaire dans moustache

{{ compteur ? 'il est true' : 'il est faut' }}

Insérer du html brut : v-html

        <p v-html="htmlBrut"></p>

         data: {
            htmlBrut: "<b>sdfsdf</b>",
        },

Fonction dans moustache

{{ checkValeur() }}

Valeur 'computed'

Si la valeur compteur change alors appelle la méthode memo()

{{ memo }}

 <script>
    new Vue ({
        el : '#mon-app',
        data: {
            compteur: 0,
        },
        methods: {
            }
        },
        computed : {
            memo: function () {
                console.log("change valeur")

            }
    })
</script>

Ou

<div>{{texteMaj}}</div>

    data: {
        TexteMaj: 'Samuel Gondouin',
    },
    computed : {
        TexteMaj: function () {
            return this.texte.toUpperCase();           
        }  

Watch

Surveille une valeur

{{ compteur }}
<button v-on:click="compteur++">Inc</button>

data: {
    compteur: 0,
},
watch : {
    compteur: function (valeur) {
        if(this.compteur == 10) {
                console.log("change valeur");
                this.compteur = 0;
            }  
        }
     }

CSS dans div ============

    <div v-bind:class="{ red : toggleColor}" >

    data: {
        toggleColor: true,
    },

Ou

    <div v-bind:class="{ myCSS, red : toggleColor}" >

    data: {
        toggleColor: true,
        myCSS : true
    },

Ou

    <div v-bind:class="objCSS" >

    data: {
        toggleColor: true,
    },
    computed: {
        objCSS: function() {
            return {
                red: this.toggleColor,
                myCSS: true
            }
        }
    }

Tableau de class

 <div v-bind:class="[objCSS, 'otherClass']" >

Inline CSS

<p :style="{color : 'blue'}">

ou

<p :style="{backgroundColor : 'blue'}">

ou

<p :style="{myStyle}">

computed: {
    myStyle: function() {
        return {
            backgroundColor : this.myColor,
            width: this.myWidth + "px"
        }
    }
}

Condition

<button v-on:click="toggleButton = !toggleButton">toggle</button>

<div v-if="toggleButton" class="box red"></div>
<p v-else="toggleButton">Sinon<>

Ou

 <p v-if="num === 1">valeur 1</p>
 <p v-else-if="num === 2">valeur 2</p>
 <p v-else-if="num === 3">valeur 3</p>
 <p v-else>autre valeur</p> 

Rendu html conditionnel

<template v-if="toggleButton">
TEXT
</template>

Boucle

<ul>
<li v-for="number in tableau"> {{ number }} </li>
</ul>

data {
    tableau : [1, 2, 3]
}

Boucle

<div v-for="(elem, index) in elems">
    {{ elems }}        
    <button v-on:click="supprimer(index)">Supprime</button>
</div>

data {
    elems : ["premier", "deuxieme"]
},
 methods : {
    supprimer: function(index) {
        this.elems.splice(index,1);
    }
}

Itération tableau

<ul>
    <li v-for="(texte, index) in tableau"> {{ index }} {{ texte }} </li>
</ul>

data {
tableau : ["aa", "bb", "cc"]
}

Itération sur objet

<ul>
    <li v-for="(val, props) in tableau"> {{ props }} : {{ val }} </li>
</ul>

data {
        objetChat : {
                race : "persan",
                age : 3,
                poids : "3 kg"
            }      
}

Itération tableau d'objet

<ul>
    <li v-for="obj in objetChat"> 
         <div v-for="(val, props) in obj"> {{ props }} : {{ val }} </div>
    </li>
</ul>

data {
     objetChat : [
                    {race : "persan", age : 3, poids : "3 kg"},
                    {race : "test", age : 3, poids : "3 kg"},
                    {race : "coucou", age : 3, poids : "3 kg"},
                 ]
}

Instance

<script>
        const instance1 = new Vue ({
                    el : '#mon-app1',
                  data: {
                    text: 'coucou1'
                },                  
            })

        const instance2 = new Vue ({
                    el : '#mon-app2',
                    data: {
                    },     
                    methods : {
                        changeTexte: function () {
                            instance1.texte = "Nouveau texte"
                        }
                    }             
            })

</script>

Composant Global

<div id="mon-app1">
    <mon-premier-composant></mon-premier-composant>  ou <mon-premier-composant/>
</div>

<script>
    Vue.component('mon-premier-composant', {
        template: '<p>Texte du composant {{ nom }}</p>',
        data: function() {
            return {
                nom : "Prenom Nom"
            },
        methods: {
        }
    })

    const instance1 = new Vue ({
                el : '#mon-app1',
              data: {
                text: 'coucou1'
            },                  
        })

</script>

ou

<div id="mon-app1">
    <MonPremierComposant></MonPremierComposant> ou <MonPremierComposant/>
</div>

<script>

    Vue.component('MonPremierComposant', {
        template: '<p>Texte du composant {{ nom }}</p>',
        data: function() {
            return {
                nom : "Prenom Nom"
            },
        methods: {
        }
    })

    const instance1 = new Vue ({
                el : '#mon-app1',
              data: {
                text: 'coucou1'
            },                  
        })

</script>

Composant Global et passage de paramètre

<div id="app">
    <comp texte="Samuel"></comp>
</div>

<script>
    Vue.component('comp', {
        props: ['texte'],
        template: '<div>Bonjour {{ texte }} </div>'
    }),

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

</script>

Ou

<div id="app">
    <comp texte="Samuel"></comp>
</div>

<script>
    Vue.component('comp', {
        props: ['texte'],
        template: '<div>Bonjour {{ texte1 }} </div>',
        data: function () {
            return {
                texte1 = this.texte
            }
        }
    }),

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

</script>

Vue CLI

vue create my-project

Structure

components/Contenu.vue :

<template>
    {{ txt }}
</template>

<script>
    export default {
        data: function () {    ou data() {
            return txt : 'coucou'
        }
    }
</script>

<style>

</style>

main.js :

import Contenu from 'components/Contenu.vue'

Vue.compontent('contenu', Contenu)

App.vue :

<template>
   <contenu></contenu>
</template>

Ou

components/Contenu.vue :

<template>
    {{ txt }}
</template>

<script>
    export default {
        name: 'Contenu'
        data() {
            return txt : 'coucou'
        }
    }
</script>

<style>

</style>

App.vue :

<template>
   <contenu></contenu>
</template>

<script>
    import Contenu from 'components/Contenu.vue'

    export default {
        name: 'App',
        components: { 
            'contenu': Contenu
        }
    }
</script>

CSS

<style scoped src="mycss.css">

</style>

Prop : Parent -> Enfant

Enfant :

<template>
   {{ prenom }}
</template>

<script>
    export default {  
        props: ['prenom']    <= Va recevoir 'prenom'
    }
</script>

Parent :

<script>

    <enfant v-bind:prenom="prenom"></enfant>

    export default {
        name: 'App',
        data() {
            return {
                prenom : 'sam'
            }
        }
    }
</script>

Prop Enfant -> Parent avec emit

Parent :

<template>
   {{ titre }}
   <div v-on:changeTitre="changementTitre($event)">change titre</div>
</template>

<script>

    export default {
        name: 'App',
        data() {
            return {
                titre : 'sam'
            }
        },
         methods: {
            changementTitre: function(nouveauTitre) {
                this.titre = nouveauTitre
            }
         }
    }
</script>

Enfant :

<template>
   <div v-on:click="changeTitre">change titre</div>
</template>

<script>
    props: ['prenom'],
    methods: {
        changeTitre: function() {
            this.$emit('changeTitre', 'mon nouveau titre')
        }
    }
</script>

Méthode

<template>
   {{ reversing() }}
</template>

<script>
    props: ['prenom'],
    methods: {
        reversing: function() {
            return this.prenom.split('').reverse().join('')
        }
    }
</script>

Bus à événement

Hook

<script>

    export default {
            created() {
            }
    }

Methode

    <div id="mon-app">
       <input type="text" v-model="nom">
       <input type="button" v-model="Clique" v-on:click="traitement">
    </div>
    {{ cases }}

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            nom : '',
        },     
      methods: {
        traitement: function() {
            alert('bonjour ' + this.nom);
        }                 
    })
</script>

Methode avec argument

    <div id="mon-app">
       <input type="text" v-model="nom">
       <input type="button" v-model="Clique" v-on:click="traitement('Bonjour')">
    </div>
    {{ cases }}

  <script>
    new Vue ({
        el : '#mon-app',
        data: {
            nom : '',
        },     
      methods: {
        traitement: function(texte) {
            alert(text + ' ' + this.nom);
        }                 
    })
</script>

$event

{{ ey }}
<img src="image.jpg" v-on:mousemove="coord($event)">

     data: {
            xy : '',
        },     
      methods: {
        coord: function(ev) {
           this.xy = 'x= ' + ev.offsetX + ', y= ' ev.offsetY;
        }     

Event Modifier preventDefault et stopPropagation

<div v-on:keydown="actionParent">
    <input type="text" v-on:keydown="action($event)>
</div> 

      methods: {
       action: function(ev) {
           console.log("input");
           ev.preventDefault();  // n'effetue pas le traitement pas défaut : N'affiche rien
           ev.stopPropagation(); // Ne propage rien vers les parents
        },       
        actionParent: function() {
           console.log("Event propage");
        },     

ou

<div v-on:keydown="actionParent">
    <input type="text" v-on:keydown.prevent.stop="action($event)>
</div> 

      methods: {
       action: function(ev) {
           console.log("input");
        },       
        actionParent: function() {
           console.log("Event propage");
        }, 

Event Modifier preventDefault et stopPropagation ================================================

 <form>
    <input type="number" v-model="nombre">
    <input type="submit" v-on:click="carre($event)">
 </form>

      methods: {
       carre: function(ev) {

           ev.preventDefault();  // n'effetue pas le traitement pas défaut : Ne vas pas recharger la page
           this.nombre = this.nombre * this.nombre;
        },            

Event Modifier

<img src="image.jpg" v-bind:width="larg" v-on:click.left="largeur(300)">

   data: {
        larg : 100,
    },     
  methods: {
    largeur: function(lar) {
       this.lar =  lar;
    }           

Arguments dynamiques

<element v-on:[evenement]="traitement"></element>
<element v-bind:[attribut]="valeur"></element>        

Soit : Sélectionne le type de click pour changer l'image

<input type="radio" value="click" v-model="choix" checked>Simple clic
<input type="radio" value="doubleclick" v-model="choix" checked>double clic        
<img v-bind:src="adresse' v-on:[choix]="change" width="400">

   data: {
        adresse: 'image/chat.jpg',
        choix: 'click'
    },     
  methods: {
    change: function() {
       if(this.adresse.indexOf('chat') != -1 ) {
            this.adresse = "image/chat.jpg";
       } else {
            this.adresse = "image/chien.jpg";
       }
    }                   

Boucle v-for pour JSON

    <ul v-for="personne in personnes">
        <li>{{personne.nom}} {{personne.prenom}}</li>
    </ul>

   data: {
            personnes : [
                    {prenom: 'Samuel', nom: 'Gondouin'},
                    {prenom: 'Chloé', nom: 'Poirier'},
                ],
        },       

Gestion des événements clavier : keyup et click

<input type="text" v-model="texte" v-on:keyup="action($event)">
<input type="button" value="Clique" v-on:click="action($event)"> 

  methods: {
    action: function() {
       if( ev.key == 'Enter' || ev.type == 'click' ) {
            this.texte = this.texte.toUpperCase();
       }
    }         

Plusieurs classes conditionnelles

<style>
    .rouge {
        color: red;
        }    
    .taille {
        font-weight: bold;
        }
</style>

 <div v-bind:class="{rouge: test, taille: test1}">texte</div>

        data: {
            test: false,
            test1: true
        },

Condition

<div v-if="cond1">
    contenu 1
</div>

<div v-else-if="cond2">
    contenu 2 
</div>

<div v-else="cond3">
    contenu 3
</div>

<div v-else>
    contenu 4
</div>

Ou

<div v-show="condition">

Slot simple

Slot nommée

Slot avec porté / Scoped slot


Filtre global et local

<div id="app">
    <input type="text" v-model="texte">
    <div>{{ texte | capglobal}}</div>
    <div>{{ texte | capglocal}}</div>
</div>

<script>

Vue.filter('capglobal', function(valeur) {
    return valeur.toUpperCase()
})

new Vue ({
   el : '#app',
   data: {
        texte: '',
    }, 
    filters: {
        caplocal: function(valeur) {
            return valeur.toUpperCase()
        }
    }
  })
  </script>