J'ai parcouru la documentation de Vue et à moins que je ne sois aveugle, je ne vois rien qui indique que les observateurs ne peuvent pas être utilisés sur les composants enfants pour les composants parents, ou dans mon cas, pour les propriétés globales de mixin. Cependant, pour une raison quelconque, je ne peux pas faire fonctionner le mien ...
J'ai un mixin global qui est utilisé pour verrouiller / déverrouiller le défilement de la fenêtre. Très simplement, j'essaie d'écouter un changement de la propriété booléenne bodyLocked sur le mixin global à partir d'un composant enfant.
Pour une raison quelconque, l'observateur se déclenche au chargement de la page , mais après cela, il ne semble pas écouter les changements.
Voici mon mixin (il est utilisé globalement avec Vue.mixin () ):
export default {
watch: {
bodyLocked: function(locked) {
console.log('locked: ' + locked);
}
}
}
Voici un exemple de composant enfant:
export default {
data() {
return {
bodyLocked: false
}
},
methods: {
/**
* Lock the DOM body to disable scrolling.
*
* @return void
*/
_lockBody() {
this.bodyLocked = true;
document.documentElement.classList.add('no-scroll');
},
/**
* Unlock the DOM body to enable scrolling.
*
* @return void
*/
_unlockBody() {
this.bodyLocked = false;
document.documentElement.classList.remove('no-scroll');
}
}
};
3 Réponses :
Les observateurs sont destinés à surveiller les propriétés calculées et d'état dans le même composant. Un composant est essentiellement un objet avec une fermeture, donc ce que vous prévoyez ne peut pas fonctionner.
De la documentation Vue pour mixin:
Les mixins sont un moyen flexible de distribuer des fonctionnalités réutilisables pour Composants Vue. Un objet mixin peut contenir toutes les options de composant. Quand un composant utilise un mixin, toutes les options du mixin seront «mixées» dans les propres options du composant.
Lorsque votre mixin global est déclaré, chaque composant Vue de votre application aura ses propres données verrouillées avec 2 méthodes _lockBody et _unlockBody pour modifier sa propre valeur verrouillé . Je crois que vous vous attendez à ce que la valeur déclarée dans le mixin global soit partagée entre les composants, mais ce n'est pas le cas. Ce que vous recherchez peut être une gestion globale de l'état à la place: https://vuejs.org /v2/guide/state-management.html
Oui, je m'en suis rendu compte quand j'ai ajouté console.log ('monté') au hook monté sur le mixin, il a été déclenché plusieurs fois ... j'hésite à utiliser la gestion de l'état car je pense que cela peut être un peu exagéré pour ce cas d'utilisation particulier. Qu'est-ce que tu en penses?
Lorsque vous utilisez un mixage global, les composants ne partagent pas la même instance des données bodyLocked . Donc, le changer dans un composant ne le changera pas dans les autres. Chaque composant aura sa propre valeur bodyLocked .
Une autre façon de faire cela, au lieu d'utiliser un mixin global, serait de partager un objet sur le prototype Vue. Un tel objet serait partagé entre toutes les instances de composant. Cela donnerait également un espace de noms plus clair dans les composants et devrait avoir un impact sur les performances inférieur à un mixin global.
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script> <div id="app"> <button @click="$bodyLocker.lock">Lock</button> <button @click="$bodyLocker.unlock">Unlock</button> </div>
.no-scroll {
background-color: #f00;
}
const locker = Vue.observable({
locked: false,
lock () {
locker.locked = true;
document.documentElement.classList.add('no-scroll');
},
unlock () {
locker.locked = false;
document.documentElement.classList.remove('no-scroll');
}
});
Vue.prototype.$bodyLocker = locker;
new Vue({
el: '#app',
watch: {
'$bodyLocker.locked' (locked) {
console.log('watcher fired: ' + locked);
}
}
});
C'est très intéressant, et c'est exactement le genre de solution avec laquelle j'aimerais aboutir ... Existe-t-il une documentation sur observable ? c'est-à-dire que Vue nous encourage à l'utiliser? Aussi, pendant que vous y êtes, savez-vous pourquoi je ne peux pas utiliser _locked comme nom de propriété? Je l'ai utilisé avant et l'observateur ne s'est pas déclenché, mais lorsque j'ai supprimé le trait de soulignement, cela a parfaitement fonctionné ... Je n'ai rien pu trouver dans la documentation concernant les traits de soulignement non autorisés dans les noms de propriété
Documents observables: vuejs.org/v2/api/#Vue-observable . Pourquoi vous ne pouvez pas utiliser _ ou $ comme préfixe dans data est expliqué ici: vuejs.org/v2/api/#data . Lisez également la section Explication détaillée ici: vuejs.org/v2/style-guide/#Private-property-names-essential pour en savoir plus sur l'utilisation de ces préfixes.
Fantastique, merci. Je vais jouer avec cela et accepter la réponse si je suis capable de le faire fonctionner correctement
Êtes-vous sûr que vous pouvez placer des fonctions dans une vue observable? Je suppose que j'appelle simplement ces fonctions comme ceci: this. $ BodyLocker.lock () ?
En outre, y a-t-il un moyen de mettre une sorte de montre dans l'observable? Je voudrais idéalement regarder la valeur locker.locked puis mettre à jour la classe no-scroll lors du changement de cette valeur. En d'autres termes, lock () sera simplement locker.locked = true , puis l'observateur mettra à jour la classe nécessaire ... Cela semble juste plus propre que d'avoir la classe mise à jour et mise à jour des propriétés dans chaque fonction. Je peux mettre à jour ma question si ce n'est pas clair ...
@BenCarey Oui, c'est bien d'y mettre des fonctions. Vous pouvez sauter à travers des cercles pour rendre les propriétés de la fonction non réactives, mais cela ne semble pas en valoir la peine. Oui, vous les appelleriez en utilisant this. $ BodyLocker.lock () . Non, vous ne pouvez pas y mettre de montre , mais vous pouvez mettre une montre sur l'un des composants pour le faire, peut-être celui que vous créez en utilisant nouvelle Vue . Donc, dans l'exemple que j'ai donné dans ma réponse, vous pourriez mettre la manipulation de classe dans le watch plutôt que d'avoir une journalisation de la console.
Je pensais que cela pourrait être le cas en ce qui concerne l'observateur ... je vais réfléchir et revenir vers vous
Je viens de réaliser quelque chose, pourquoi utilisez-vous locker.locked et pas this.locked ? ceci fait sûrement référence à l'objet actuel?
La raison pour laquelle je pose la question est que je place mon observable dans un fichier séparé observables / VueNoScroll / index.js , puis que j'utilise importer VueNoScroll depuis './observables/VueNoScroll' . Ainsi, le contenu de index.js se lit comme export default {...
@BenCarey J'ai évité d'utiliser this pour m'assurer que les fonctions fonctionneraient même si elles ne sont pas appelées avec un contexte this approprié. Dans mon exemple, les boutons utilisent @click = "$ bodyLocker.lock" , ce qui perdrait le contexte this . J'aurais pu les écrire comme @click = "$ bodyLocker.lock ()" pour résoudre ce problème, ou j'aurais pu utiliser bind pour lier le contexte sur ces fonctions, mais Je suis allé avec une fermeture à la place.
Cela a du sens, j'utiliserai ceci car il convient à mon cas d'utilisation