Skip to content

Latest commit

 

History

History
193 lines (142 loc) · 7.39 KB

adding-instance-properties.md

File metadata and controls

193 lines (142 loc) · 7.39 KB
title type order
Ajouter des propriétés aux instances
cookbook
1.1

Exemple simple

Il peut y avoir des données/utilitaires que vous aimeriez utiliser dans de nombreux composants, mais vous ne voulez pas polluer le scope global. Dans ces cas-là, vous pouvez les rendre accessibles dans chaque instance Vue en les définissant dans le prototype :

Vue.prototype.$appName = 'Mon App'

Maintenant, $appName sera accessible dans toutes les instances Vue, même avant leur création. Si nous exécutons :

new Vue({
  beforeCreate: function () {
    console.log(this.$appName)
  }
})

Alors "Mon App" sera affiché en console. C'est aussi simple !

L'importance de la portée des propriétés d'instances

Il se peut que vous vous demandiez :

"Pourquoi appName commence par un $ ? Est-ce important ? Qu'est-ce que ça fait ?

Aucune magie n'a lieu ici. $ est simplement une convention que Vue utilise pour les propriétés qui sont accessibles dans toutes les instances. Cela évite les conflits avec toutes les autres données définies, propriétés calculées ou méthodes.

"Conflits ? Qu'est-ce que ça signifie ?"

Une autre bonne question ! Si vous faites juste :

Vue.prototype.appName = 'My App'

Alors qu'est-ce qui sera affiché ci-dessous d'après vous ?

new Vue({
  data: {
    // Uh oh - appName est *aussi* le nom de la
    // propriété d'instance que nous venons de définir !
    appName: "Le nom d'une autre app"
  },
  beforeCreate: function () {
    console.log(this.appName)
  },
  created: function () {
    console.log(this.appName)
  }
})

Cela sera "Le nom d'une autre app", puis "Mon App", car this.appName est écrasé (en quelques sortes) par data quand l'instance est créée. Nous limitons la portée des propriétés avec $ pour éviter ça. Vous pouvez même utiliser votre propre convention si vous préférez, comme $_appName ou ΩappName, pour en plus prévenir les conflits avec les plugins et les fonctionnalités futures.

Un exemple en situation réelle : Remplacer Vue Resource avec Axios

Disons vous remplacez le maintenant déprécié Vue Resource. Vous aimiez vraiment accéder aux méthodes de requête avec this.$http et vous voulez faire la même chose avec Axios à la place.

Tout ce que vous avez à faire est inclure axios dans votre projet :

<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.2/axios.js"></script>

<div id="app">
  <ul>
    <li v-for="user in users">{{ user.name }}</li>
  </ul>
</div>

Puis assigner axios à Vue.prototype.$http :

Vue.prototype.$http = axios

Alors vous serez capables d'utiliser des méthodes comme this.$http.get dans n'importe quelle instance Vue :

new Vue({
  el: '#app',
  data: {
    users: []
  },
  created () {
    var vm = this
    this.$http.get('https://jsonplaceholder.typicode.com/users')
      .then(function (response) {
        vm.users = response.data
      })
  }
})

Le Contexte des Méthodes du Prototype

Au cas où vous ne seriez pas au courant, les méthodes ajoutées au prototype en JavaScript obtiennent le contexte de l'instance. Cela signifie qu'elles peuvent utiliser this pour accéder aux data, propriétés calculées, méthodes ou toute autre chose définie dans l'instance.

Profitons de ceci dans une méthode $reverseText :

Vue.prototype.$reverseText = function (propertyName) {
  this[propertyName] = this[propertyName].split('').reverse().join('')
}

new Vue({
  data: {
    message: 'Hello'
  },
  created: function () {
    console.log(this.message)    // => "Hello"
    this.$reverseText('message')
    console.log(this.message)    // => "olleH"
  }
})

Notez que la liaison du contexte ne fonctionnera pas si vous utiliez une fonction fléchée ES6/2015, puisqu'elles gardent implicitement le contexte parent. Cela signifie que la version avec une fonction fléchée :

Vue.prototype.$reverseText = propertyName => {
  this[propertyName] = this[propertyName].split('').reverse().join('')
}

rejettera une exception :

Uncaught TypeError: Cannot read property 'split' of undefined

Quand faut-il éviter ce pattern ?

Tant que vous êtes vigilants à la portée des propriétés du prototype, utiliser ce pattern est plutôt sûr - c'est-à-dire, peu probable de produire des bugs.

Cependant, il peut parfois causer de la confusion auprès des autres développeurs. Ils peuvent voir this.$http, par exmeple, et penser, "Oh, je ne savais pas qu'il s'agissait d'une fonctionnalité de Vue !". Ensuite ils vont sur un projet différent et sont confus quand this.$http est non défini. Ou alors ils cherchent sur Google comment faire quelque-chose, mais ne trouvent pas de résultats car ils ne réalisent pas qu'ils utilisent Axios sous un alias.

La commodité vient au prix de l'explicité. En regardant simplement un composant, il est impossible de dire d'où $http vient. Vue lui-même ? Un plugin ? Un collègue ?

Alors quelles sont les alternatives ?

Patterns Alternatifs

Quand ne pas utiliser un système de modules

Dans les applications sans systèmes de modules (ex. via Webpack ou Browserify), il y a un pattern souvent utilisé dans n'importe quel front-end amélioré en JavaScript : un objet global App.

Si ce que vous voulez ajouter n'a rien à voir avec Vue spécifiquement, cela peut être une bonne alternative à étudier. Voici un exemple :

var App = Object.freeze({
  name: 'Mon App',
  description: '2.1.4',
  helpers: {
    // Ceci est une version purement fonctionnelle
    // de la méthode $reverseText décrite plus haut
    reverseText: function (text) {
      return text.split('').reverse().join('')
    }
  }
})

Si vous avez levé un sourcil à `Object.freeze`, cela sert à empêcher l'objet d'être modifié dans le futur. Il s'agit essentiellement de rendre toutes ses propriétés constantes, les protégeant de futurs bugs d'état.

Maintenant la source de ces propriétés partagées est bien plus évidente : il y a un objet App défini quelque-part dans l'application. Pour le trouver, les développeurs ont seulement besoin de rechercher la référence dans le projet.

Un autre avantage est que App peut maintenant être utilisé n'importe où dans le code, qu'il soit lié à Vue ou non. Cela inclue les valeurs attachées directement aux options des instances, plutôt qu'avoir à entrer dans une fonction pour accéder aux propriétés avec this :

new Vue({
  data: {
    appVersion: App.version
  },
  methods: {
    reverseText: App.helpers.reverseText
  }
})

Quand utiliser un système de modules

Quand vous avez accès à un système de modules, vous pouvez facilement organiser le code partagé à travers des modules, puis require/import ces modules partout où ils sont nécessaires. C'est l'exemple parfait de l'explicité, car chaque fichier obtient alors une liste de dépendances. Vous savez exactement d'où vient chacune d'entre elles.

Bien que certainement plus verbeux, cette approche est assurément la plus maintenable, particulièrement quand vous travaillez avec d'autres développeurs et/ou construisez une large application.