2 votes

Vue liaison de propriété bidirectionnelle

Voici ma structure actuelle (qui ne fonctionne pas).

Composant parent:

import Field from './input/Field'
export default {
  components: {
    'field-input': Field
  },
  data() {
    return {
      title: {
        value: '',
        warn: false
      }
    }
  }
}

Composant enfant:

export default {
  props: ['field']
}

Les exigences sont les suivantes :

  • Si la valeur title.warn des données du parent change, le bind de la classe de l'enfant doit être mis à jour (field.warn).
  • Si l' de l'enfant est mis à jour (field.value), alors la valeur de title.value du parent doit être mise à jour.

Quelle est la solution la plus propre pour y parvenir ?

8voto

acdcjunior Points 19898

Ne liez pas l'élément du composant enfant à la valeur title.value du parent (comme ). Il s'agit d'une mauvaise pratique connue, capable de rendre le flux de données de votre application beaucoup plus difficile à comprendre.

Les exigences sont les suivantes :

  • Si la valeur de title.warn du parent change, le bind de la classe de l'enfant doit être mis à jour (field.warn).

C'est simple, créez simplement une propriété warn et passez-la du parent à l'enfant.

Parent (passant la prop à l'enfant) :

Enfant/template (utilisant la prop -- lecture uniquement) :

Texte quelconque

Enfant/JavaScript (déclarant la prop et son type attendu) :

export default {
  props: {warn: Boolean}
}

Remarquez que dans le template, c'est !warn, pas !title.warn. De plus, vous devriez déclarer warn comme une prop de type Boolean car sinon le parent pourrait utiliser une chaîne de caractères (par exemple ) ce qui donnerait des résultats inattendus (!"false" est en réalité false, pas true).

  • Si l'élément de l'enfant est mis à jour (field.value), alors la valeur title.value du parent doit être mise à jour.

Vous avez plusieurs options possibles ici (comme utiliser .sync dans une prop), mais je soutiendrais que la solution la plus propre dans ce cas est de créer une propriété value et d'utiliser v-model sur le parent.

Parent (liaison de la prop en utilisant v-model) :

Enfant/template (utilisant la prop comme valeur initiale et émettant des événements input lorsqu'elle change) :

Enfant/JavaScript (déclarant la prop et son type attendu) :

export default {
  props: {value: String}
}

Cliquez ici pour une DÉMO fonctionnelle de ces deux solutions ensemble.

0voto

R34lthing Points 160

Il existe plusieurs façons d'obtenir une liaison de données bidirectionnelle :

  1. Utilisez des props sur les composants
  2. Utilisez l'attribut v-model
  3. Utilisez le modificateur sync
  4. Utilisez Vuex

Pour les liaisons bidirectionnelles, gardez à l'esprit que cela peut entraîner une chaîne de mutations difficiles à maintenir, cité de la documentation :

Malheureusement, une vraie liaison bidirectionnelle peut poser des problèmes de maintenance, car les composants enfants peuvent muter le parent sans que la source de cette mutation soit évidente à la fois dans le parent et dans l'enfant.

Voici quelques détails sur les méthodes disponibles :

1.) Utilisez des props sur les composants

Utiliser des props pour une liaison bidirectionnelle n'est pas généralement recommandé mais possible, en passant un objet ou un tableau vous pouvez changer une propriété de cet objet et elle sera observée à la fois dans l'enfant et dans le parent sans que Vue n'affiche un avertissement dans la console.

À chaque fois que le composant parent est mis à jour, toutes les props dans le composant enfant seront actualisées avec la dernière valeur. Cela signifie que vous ne devez pas essayer de muter une prop à l'intérieur d'un composant enfant

Les props sont faciles à utiliser et sont le moyen idéal pour résoudre la plupart des problèmes courants.
En raison de la façon dont Vue surveille les changements toutes les propriétés doivent être disponibles sur un objet sinon elles ne seront pas réactives. Si des propriétés sont ajoutées après que Vue a terminé de les rendre observables, 'set' devra être utilisé.

 //Utilisation normale
 Vue.set(uneVariable, 'uneNouvelleProp', 42);
 //Voici comment l'utiliser dans Nuxt
 this.$set(this.historyEntry, 'date', new Date());

L'objet sera réactif pour le composant et le parent :

Si vous passez un objet/tableau en tant que prop, la synchronisation bidirectionnelle se fait automatiquement - changez les données dans le enfant, elles sont également modifiées dans le parent.

Si vous passez des valeurs simples (chaînes, nombres) via des props, vous devez explicitement utiliser le modificateur .sync

Comme cité dans --> https://stackoverflow.com/a/35723888/1087372

2.) Utilisez l'attribut v-model

L'attribut v-model est du sucre syntaxique qui permet une liaison bidirectionnelle facile entre le parent et l'enfant. Il fait la même chose que le modificateur sync, seulement il utilise une prop spécifique et un événement spécifique pour la liaison

Ceci :

est la même chose que ceci :

Où la prop doit être value et l'événement doit être input

3.) Utilisez le modificateur sync

Le modificateur sync est également du sucre syntaxique et fait la même chose que v-model, seulement que les noms de prop et d'événement sont définis par ce qui est utilisé.

Il peut être utilisé dans le parent comme suit :

Depuis l'enfant, un événement peut être émis pour notifier le parent de tout changement :

 this.$emit('update:title', nouveauTitre)

4.) Utilisez Vuex

Vuex est un magasin de données accessible depuis chaque composant. Les changements peuvent être souscrits.

En utilisant le magasin Vuex, il est plus facile de voir le flux des mutations des données et ils sont explicitement définis. En utilisant les outils de développement Vue il est facile de déboguer et d'annuler les changements qui ont été faits.

Cette approche nécessite un peu plus de boilerplate, mais si elle est utilisée dans tout un projet, elle devient une manière beaucoup plus propre de définir comment les changements sont faits et d'où ils proviennent.

Voir le guide de démarrage

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X