Passer des données aux composants dans vue.js


92

J'ai du mal à comprendre comment transmettre des données entre les composants dans vue.js. J'ai lu plusieurs fois la documentation et examiné de nombreuses questions et didacticiels liés à la vue, mais je ne comprends toujours pas.

Pour comprendre cela, j'espère obtenir de l'aide pour compléter un exemple assez simple

  1. afficher une liste d'utilisateurs dans un composant (terminé)
  2. envoyer les données utilisateur à un nouveau composant lorsqu'un lien est cliqué (terminé) - voir mise à jour en bas.
  3. modifier les données utilisateur et les renvoyer au composant d'origine (je ne suis pas arrivé jusqu'ici)

Voici un violon, qui échoue à la deuxième étape: https://jsfiddle.net/retrogradeMT/d1a8hps0/

Je comprends que je dois utiliser des accessoires pour transmettre des données au nouveau composant, mais je ne sais pas comment le faire fonctionnellement. Comment lier les données au nouveau composant?

HTML:

    <div id="page-content">
       <router-view></router-view>
     </div>

 <template id="userBlock" >
   <ul>
     <li v-for="user in users">{{user.name}} - <a v-link="{ path: '/new' }"> Show new component</a>
     </li>
   </ul>
 </template>

  <template id="newtemp" :name ="{{user.name}}">
    <form>
      <label>Name: </label><input v-model="name">
      <input type="submit" value="Submit">
    </form>
  </template>

js pour le composant principal:

Vue.component('app-page', {
  template: '#userBlock',

  data: function() {
    return{

        users: []
      }
    },

ready: function () {
    this.fetchUsers();
},

methods: {
    fetchUsers: function(){
        var users = [
          {
            id: 1,
            name: 'tom'
          },
          {
            id: 2,
            name: 'brian'
          },
          {
            id: 3,
            name: 'sam'
          },
        ];

        this.$set('users', users);
     }
    }
  })

JS pour le deuxième composant:

Vue.component('newtemp', {
  template: '#newtemp',
  props: 'name',
  data: function() {
    return {
        name: name,
        }
   },
})

MISE À JOUR

Ok, j'ai compris la deuxième étape. Voici un nouveau violon montrant la progression: https://jsfiddle.net/retrogradeMT/9pffnmjp/

Parce que j'utilise Vue-router, je n'utilise pas d'accessoires pour envoyer les données à un nouveau composant. Au lieu de cela, j'ai besoin de définir des paramètres sur le lien v, puis d'utiliser un hook de transition pour l'accepter.

Les changements de V-link voient les routes nommées dans la documentation vue-router :

<a v-link="{ name: 'new', params: { name: user.name }}"> Show new component</a>

Puis sur le composant, ajoutez des données aux options d'itinéraire voir les crochets de transition :

Vue.component('newtemp', {
  template: '#newtemp',
  route: {
   data: function(transition) {
        transition.next({
            // saving the id which is passed in url
            name: transition.to.params.name
        });
     }
  },
 data: function() {
    return {
        name:name,
        }
   },
})

Réponses:


46

------------- Ce qui suit ne s'applique qu'à Vue 1 --------------

La transmission des données peut se faire de plusieurs manières. La méthode dépend du type d'utilisation.


Si vous souhaitez transmettre des données de votre html pendant que vous ajoutez un nouveau composant. Cela se fait à l'aide d'accessoires.

<my-component prop-name="value"></my-component>

Cette valeur de prop ne sera disponible pour votre composant que si vous ajoutez le nom de prop prop-nameà votre propsattribut.


Lorsque des données sont transmises d'un composant à un autre composant en raison d'un événement dynamique ou statique. Cela se fait en utilisant des répartiteurs d'événements et des diffuseurs. Par exemple, si vous avez une structure de composant comme celle-ci:

<my-parent>
    <my-child-A></my-child-A>
    <my-child-B></my-child-B>
</my-parent>

Et vous souhaitez envoyer des données de <my-child-A>à <my-child-B>puis, <my-child-A>vous devrez envoyer un événement:

this.$dispatch('event_name', data);

Cet événement voyagera tout le long de la chaîne parentale. Et de n'importe quel parent, vous avez une branche vers <my-child-B>vous diffusez l'événement avec les données. Donc chez le parent:

events:{
    'event_name' : function(data){
        this.$broadcast('event_name', data);
    },

Maintenant, cette émission voyagera le long de la chaîne enfant. Et quel que soit l'enfant à qui vous souhaitez participer, dans notre cas, <my-child-B>nous ajouterons un autre événement:

events: {
    'event_name' : function(data){
        // Your code. 
    },
},

La troisième façon de transmettre des données consiste à utiliser des paramètres dans les liens v. Cette méthode est utilisée lorsque les chaînes de composants sont complètement détruites ou dans les cas où l'URI change. Et je vois que vous les comprenez déjà.


Décidez du type de communication de données que vous souhaitez et choisissez de manière appropriée.


1
Merci, c'était vraiment utile. Le seul élément avec lequel je me débat encore est les conventions de dénomination. ie: j'ai user.name que je passe via v-link comme nom. Je peux maintenant modifier la variable de nom et la renvoyer au composant d'origine en tant que nom, mais le composant d'origine n'a pas de var appelé nom. Qu'est-ce que j'oublie ici? Ne semble pas possible de passer un objet via v-link?
rétrograde du

1
Vous passez déjà un objet. paramsest un objet. La clé de nom peut être attribuée this.user.namedans votre composant. Créez un violon si vous avez besoin d'aide et faites-le moi savoir. Vérifiez ceci: vuejs.github.io/vue-router/en/route.html
notANerdDev

Ah, ok je l'ai maintenant. Merci encore. J'apprécie votre aide, cela a vraiment rendu les choses beaucoup plus claires.
rétrograde le

6
Réponse géniale, mais si je comprends bien, cela ne fonctionnera pas avec la version 2.0, car les événements sont obsolètes?
rix

2
J'ai adoré la réponse mais je suis arrivé aux commentaires et comme je travaille avec Vue 2, je sens que je ne vais pas pouvoir utiliser la deuxième méthode suggérée par vous. Est-ce que cela est correctement craint?
Konrad Viltersten

23

La meilleure façon d'envoyer des données d'un composant parent à un enfant consiste à utiliser des accessoires .

Transmettre des données de parent à enfant via props

  • Déclarer props(tableau ou objet ) dans l'enfant
  • Passez-le à l'enfant via <child :name="variableOnParent">

Voir la démo ci-dessous:

Vue.component('child-comp', {
  props: ['message'], // declare the props
  template: '<p>At child-comp, using props in the template: {{ message }}</p>',
  mounted: function () {
    console.log('The props are also available in JS:', this.message);
  }
})

new Vue({
  el: '#app',
  data: {
    variableAtParent: 'DATA FROM PARENT!'
  }
})
<script src="https://unpkg.com/vue@2.5.13/dist/vue.min.js"></script>

<div id="app">
  <p>At Parent: {{ variableAtParent }}<br>And is reactive (edit it) <input v-model="variableAtParent"></p>
  <child-comp :message="variableAtParent"></child-comp>
</div>


petit correctif: "<child-comp" au lieu de "<child" et variableAtParent .. Passez-le à l'enfant via <child-comp: name = "variableAtParent">
muenalan

Cela ne fonctionnera qu'avec une propriété simple, les références d'objets ne seront pas mises à jour. Par exemple, si vous avez la propriété parent être tableau et que ce tableau a été remplacé dans l'objet parent par un autre tableau, l'enfant ne le verra pas.
Stan Sokolov le

@StanSokolov pas du tout. Je travaille pour les tableaux, voir: jsfiddle.net/acdcjunior/q4mank05 . Si votre baie n'est pas réactive, vous êtes probablement confronté à un problème de réactivité. Essayez d'utiliser Vue.set, plus ici: vuejs.org/v2/guide/reactivity.html#For-Arrays
acdcjunior

A quoi ça sert s'il n'est pas réactif? Bien sûr, il était réactif avec une référence constamment remplacée par un nouveau tableau. Vue ne propage pas les "changements de référence" aux enfants, seulement les changements de valeur sur des éléments simples. Ainsi, si la référence au tableau a été écrasée dans parent, les enfants verront toujours l'ancienne référence. Je ne saurai jamais que le parent travaille maintenant avec un objet différent.
Stan Sokolov le

@StanSokolov Voir ceci: jsfiddle.net/acdcjunior/ftmrne2h le tableau est remplacé dans le parent et l'enfant le voit / y réagit (cliquez sur le bouton pour tester). Ou voulez-vous dire autre chose? Si tel est le cas, il serait utile que vous modifiiez le violon pour le montrer
acdcjunior

15

Je pense que le problème est ici:

<template id="newtemp" :name ="{{user.name}}">

Lorsque vous préfixez le prop avec, :vous indiquez à Vue qu'il s'agit d'une variable et non d'une chaîne. Vous n'avez donc pas besoin du tout {{}}autour user.name. Essayer:

<template id="newtemp" :name ="user.name">

ÉDITER-----

Ce qui précède est vrai, mais le plus gros problème ici est que lorsque vous modifiez l'URL et passez à une nouvelle route, le composant d'origine disparaît. Pour que le deuxième composant modifie les données parentes, le deuxième composant doit être un composant enfant du premier ou simplement une partie du même composant.


Merci jeff. J'ai essayé de supprimer le {{}} mais j'obtiens toujours les mêmes erreurs.
rétrograde

2

J'ai trouvé un moyen de transmettre les données parentes à la portée du composant dans Vue, je pense que c'est un peu un hack mais peut-être que cela vous aidera.

1) Données de référence dans Vue Instance en tant qu'objet externe (data : dataObj)

2) Ensuite, dans la fonction de retour de données dans le composant enfant, retournez simplement parentScope = dataObjet voilà. Maintenant, vous ne pouvez pas faire des choses comme {{ parentScope.prop }}et cela fonctionnera comme un charme.

Bonne chance!


C'est coupler les deux composants ensemble ce qui peut convenir à un arbre et à ses nœuds, mais n'est normalement pas favorisé. J'essaierais d'éviter cela.
décembre

1

Les réponses mentionnées ci-dessus fonctionnent bien, mais si vous souhaitez transmettre des données entre 2 composants frères, le bus d'événements peut également être utilisé. Consultez ce blog qui vous aidera à mieux comprendre.

supppose pour 2 composants: CompA et CompB ayant le même parent et main.js pour la configuration de l'application vue principale. Pour transmettre des données de CompA à CompB sans impliquer le composant parent, vous pouvez effectuer les opérations suivantes.

dans le fichier main.js, déclarez une instance globale de Vue distincte, qui sera le bus d'événements.

export const bus = new Vue();

Dans CompA, où l'événement est généré: vous devez émettre l'événement sur le bus.

methods: {
      somethingHappened (){
          bus.$emit('changedSomething', 'new data');
      }
  }

Maintenant, la tâche est d'écouter l'événement émis, donc, dans CompB, vous pouvez écouter comme.

created (){
    bus.$on('changedSomething', (newData) => {
      console.log(newData);
    })
  }

Avantages:

  • Moins de code propre.
  • Le parent ne doit pas impliquer de transmettre des données d'une composition enfant à une autre (à mesure que le nombre d'enfants augmente, cela deviendra difficile à maintenir)
  • Suit l'approche pub-sub.

0

J'accède aux propriétés principales en utilisant $root.

Vue.component("example", { 
    template: `<div>$root.message</div>`
});
...
<example></example>

-2

Une variable JS globale (objet) peut être utilisée pour transmettre des données entre les composants. Exemple: transmission de données d'Ammlogin.vue à Options.vue. Dans Ammlogin.vue, rspData est défini sur la réponse du serveur. Dans Options.vue, la réponse du serveur est rendue disponible via rspData.

index.html:

<script>
    var rspData; // global - transfer data between components
</script>

Ammlogin.vue:

....    
export default {
data: function() {return vueData}, 
methods: {
    login: function(event){
        event.preventDefault(); // otherwise the page is submitted...
        vueData.errortxt = "";
        axios.post('http://vueamm...../actions.php', { action: this.$data.action, user: this.$data.user, password: this.$data.password})
            .then(function (response) {
                vueData.user = '';
                vueData.password = '';
                // activate v-link via JS click...
                // JSON.parse is not needed because it is already an object
                if (response.data.result === "ok") {
                    rspData = response.data; // set global rspData
                    document.getElementById("loginid").click();
                } else {
                    vueData.errortxt = "Felaktig avändare eller lösenord!"
                }
            })
            .catch(function (error) {
                // Wu oh! Something went wrong
                vueData.errortxt = error.message;
            });
    },
....

Options.vue:

<template>
<main-layout>
  <p>Alternativ</p>
  <p>Resultat: {{rspData.result}}</p>
  <p>Meddelande: {{rspData.data}}</p>
  <v-link href='/'>Logga ut</v-link>
</main-layout>
</template>
<script>
 import MainLayout from '../layouts/Main.vue'
 import VLink from '../components/VLink.vue'
 var optData = { rspData: rspData}; // rspData is global
 export default {
   data: function() {return optData},
   components: {
     MainLayout,
     VLink
   }
 }
</script>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.