Przekazywanie danych do komponentów w vue.js


92

Staram się zrozumieć, jak przekazywać dane między komponentami w vue.js. Kilka razy przeczytałem dokumentację i przejrzałem wiele pytań i tutoriali związanych z vue, ale nadal nie rozumiem.

Aby się tym zająć, mam nadzieję, że pomogę w utworzeniu całkiem prostego przykładu

  1. wyświetlić listę użytkowników w jednym komponencie (gotowe)
  2. wysyłaj dane użytkownika do nowego komponentu po kliknięciu łącza (gotowe) - patrz aktualizacja na dole.
  3. edytuj dane użytkownika i wyślij je z powrotem do oryginalnego komponentu (nie zaszedłem tak daleko)

Oto skrzypce, które kończą się niepowodzeniem w kroku drugim: https://jsfiddle.net/retrogradeMT/d1a8hps0/

Rozumiem, że muszę użyć rekwizytów, aby przekazać dane do nowego komponentu, ale nie jestem pewien, jak to funkcjonalnie zrobić. Jak powiązać dane z nowym komponentem?

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 dla głównego składnika:

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 dla drugiego komponentu:

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

AKTUALIZACJA

Ok, wymyśliłem drugi krok. Oto nowe skrzypce pokazujące postęp: https://jsfiddle.net/retrogradeMT/9pffnmjp/

Ponieważ używam routera Vue, nie używam rekwizytów do wysyłania danych do nowego komponentu. Zamiast tego potrzebuję ustawić parametry w łączu v, a następnie użyć haka przejścia, aby to zaakceptować.

Zmiany w linku V pokazują nazwane trasy w dokumentach vue-routera :

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

Następnie w komponencie dodaj dane do opcji trasy, zobacz haki przejścia :

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,
        }
   },
})

Odpowiedzi:


46

------------- Poniższe dotyczy tylko Vue 1 --------------

Przekazywanie danych może odbywać się na wiele sposobów. Metoda zależy od rodzaju zastosowania.


Jeśli chcesz przekazać dane z html podczas dodawania nowego komponentu. Robi się to za pomocą rekwizytów.

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

Ta wartość właściwości będzie dostępna dla twojego komponentu tylko wtedy, gdy dodasz nazwę właściwości prop-namedo swojego propsatrybutu.


Gdy dane są przekazywane z komponentu do innego komponentu z powodu jakiegoś dynamicznego lub statycznego zdarzenia. Odbywa się to za pomocą dyspozytorów wydarzeń i nadawców. Na przykład, jeśli masz taką strukturę komponentów:

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

I chcesz wysłać dane od <my-child-A>do <my-child-B>wtedy w <my-child-A>będziesz musiał wysłać zdarzenie:

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

To wydarzenie przejdzie przez całą drogę w górę łańcucha nadrzędnego. I od dowolnego rodzica, do którego masz oddział <my-child-B>, transmituj wydarzenie wraz z danymi. Więc w rodzicu:

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

Teraz ta transmisja będzie przebiegać wzdłuż łańcucha potomnego. W przypadku dowolnego dziecka, które chcesz wziąć udział w wydarzeniu, w naszym przypadku <my-child-B>dodamy kolejne wydarzenie:

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

Trzecim sposobem przekazywania danych są parametry w v-linkach. Ta metoda jest używana, gdy łańcuchy komponentów są całkowicie zniszczone lub w przypadkach, gdy zmienia się identyfikator URI. I widzę, że już je rozumiesz.


Zdecyduj, jaki typ transmisji danych chcesz i wybierz odpowiednio.


1
Dziękuję, to było naprawdę pomocne. Jedyne, z czym wciąż się zmagam, to nazewnictwo konwencji. tj .: mam user.name, które przekazuję przez v-link jako nazwę. Mogę teraz edytować zmienną name i przekazać ją z powrotem do oryginalnego komponentu jako nazwę, ale oryginalny komponent nie ma zmiennej o nazwie name. Czego tu brakuje? Nie wydaje się możliwe przesłanie obiektu przez v-link?
retrogradacja

1
Już mijasz obiekt. paramsjest przedmiotem. Klucz nazwy można przypisać this.user.namew swoim komponencie. Stwórz skrzypce, jeśli potrzebujesz pomocy, i daj mi znać. Sprawdź to: vuejs.github.io/vue-router/en/route.html
notANerdDev

Ach, ok, już to mam. Dzięki jeszcze raz. Doceniam twoją pomoc, to naprawdę wszystko wyjaśniło.
retrogradacja

6
Świetna odpowiedź, ale jak rozumiem, nie będzie działać w wersji 2.0, ponieważ wydarzenia zostały wycofane?
rix

2
Podobała mi się odpowiedź, ale potem dotarłem do komentarzy, a ponieważ pracuję z Vue 2, czuję, że nie będę w stanie skorzystać z drugiej metody sugerowanej przez Ciebie. Czy słusznie się tego obawiasz?
Konrad Viltersten

23

Najlepszym sposobem na przesłanie danych z komponentu nadrzędnego do dziecka jest użycie właściwości .

Przekazywanie danych od rodzica do dziecka za pośrednictwem props

  • Zadeklaruj props(tablicę lub obiekt ) w dziecku
  • Przekaż dziecku przez <child :name="variableOnParent">

Zobacz demo poniżej:

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>


mała poprawka: „<child-comp” zamiast „<child” i variableAtParent .. Przekaż to dziecku przez <child-comp: name = "variableAtParent">
muenalan

Będzie działać tylko z prostą właściwością, odniesienia do obiektów nie będą aktualizowane. Na przykład, jeśli masz właściwość rodzica be array, a ta tablica została zamieniona w obiekcie nadrzędnym na inną tablicę, dziecko jej nie zobaczy.
Stan Sokolov

@StanSokolov wcale. Pracuję dla tablic, patrz: jsfiddle.net/acdcjunior/q4mank05 . Jeśli macierz nie jest reaktywna, prawdopodobnie masz problem z reaktywnością. Spróbuj użyć Vue.set, więcej tutaj: vuejs.org/v2/guide/reactivity.html#For-Arrays
acdcjunior

Po co, jeśli nie reaguje? Jasne, że był reaktywny, a referencje były stale zastępowane przez nową macierz. Vue nie propaguje „zmian odniesień” do dzieci, a jedynie zmiany wartości w prostych elementach. Więc jeśli odniesienie do tablicy zostało nadpisane w rodzicu, dzieci nadal będą widzieć stare odniesienie. Nigdy się nie dowiesz, że rodzic pracuje teraz z innym obiektem.
Stan Sokolov

@StanSokolov Zobacz: jsfiddle.net/acdcjunior/ftmrne2h tablica jest zastępowana w rodzicu, a dziecko widzi / reaguje na nią (kliknij przycisk, aby przetestować). Czy masz na myśli coś innego? Jeśli tak, byłoby pomocne, gdybyś wyedytował skrzypce, aby je pokazać
acdcjunior

15

Myślę, że problem jest tutaj:

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

Kiedy prefiksujesz atrybut z :you, wskazujesz Vue, że jest to zmienna, a nie łańcuch. Więc nie potrzebujesz {{}}wokół user.name. Próbować:

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

EDYTOWAĆ-----

Powyższe jest prawdą, ale większym problemem jest to, że po zmianie adresu URL i przejściu do nowej trasy oryginalny komponent znika. Aby drugi komponent mógł edytować dane nadrzędne, drugi komponent musiałby być komponentem potomnym pierwszego lub po prostu częścią tego samego komponentu.


Dzięki, Jeff. Próbowałem usunąć {{}}, ale nadal pojawiają się te same błędy.
retrogradacja

2

Znalazłem sposób na przekazanie danych nadrzędnych do zakresu komponentów w Vue, myślę, że to trochę hack, ale może to ci pomoże.

1) Dane referencyjne w instancji Vue jako obiekt zewnętrzny (data : dataObj)

2) Następnie w funkcji zwracania danych w komponencie potomnym po prostu zwróć parentScope = dataObji voila. Teraz nie możesz robić takich rzeczy jak{{ parentScope.prop }} i będą działać jak urok.

Powodzenia!


To połączenie obu komponentów razem, co może być dobre dla drzewa i jego węzłów, ale zwykle nie jest preferowane. Starałbym się tego uniknąć.
grudzień

1

Powyższe odpowiedzi działają dobrze, ale jeśli chcesz przekazywać dane między dwoma komponentami siostrzanymi, możesz również użyć magistrali zdarzeń. Zajrzyj na tego bloga, który pomoże Ci lepiej zrozumieć.

załóżmy dla 2 komponentów: CompA i CompB z tym samym rodzicem i main.js do konfiguracji głównej aplikacji vue. Aby przekazać dane z CompA do CompB bez angażowania komponentu nadrzędnego, możesz wykonać następujące czynności.

w pliku main.js zadeklaruj oddzielną globalną instancję Vue, która będzie magistralą zdarzeń.

export const bus = new Vue();

W CompA, gdzie generowane jest zdarzenie: musisz wysłać zdarzenie do magistrali.

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

Teraz zadaniem jest odsłuchanie emitowanego zdarzenia, więc w CompB możesz słuchać jak.

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

Zalety:

  • Mniej i czysty kod.
  • Rodzic nie powinien angażować się w przekazywanie danych z jednego komputera dziecka do drugiego (wraz ze wzrostem liczby dzieci trudno będzie je utrzymać)
  • Podąża za podejściem pub-sub.

0

Dostęp do głównych właściwości uzyskuję za pomocą $root.

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

-2

Globalna zmienna JS (obiekt) może służyć do przekazywania danych między komponentami. Przykład: przekazywanie danych z Ammlogin.vue do Options.vue. W Ammlogin.vue rspData jest ustawiane na odpowiedź z serwera. W Options.vue odpowiedź z serwera jest udostępniana za pośrednictwem 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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.