title | type | order |
---|---|---|
Ajouter des propriétés aux instances |
cookbook |
1.1 |
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 !
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.
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
})
}
})
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
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 ?
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 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.