Передача даних компонентам у vue.js


92

Я намагаюся зрозуміти, як передавати дані між компонентами у vue.js. Я кілька разів перечитав документи та переглянув багато питань та підручників, пов'язаних з наукою, але досі не отримую.

Щоб обернути голову навколо цього, я сподіваюся на допомогу, заповнивши досить простий приклад

  1. відобразити список користувачів в одному компоненті (готово)
  2. надсилати дані користувача до нового компонента, коли клацне посилання (зроблено) - див. оновлення внизу.
  3. відредагуйте дані користувача та надішліть їх назад до оригінального компонента (ще далеко не дійшли)

Ось скрипка, яка не вдається на другому кроці: https://jsfiddle.net/retrogradeMT/d1a8hps0/

Я розумію, що мені потрібно використовувати реквізит для передачі даних новому компоненту, але я не впевнений, як функціонально це зробити. Як прив’язати дані до нового компонента?

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 для основного компонента:

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 для другого компонента:

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

ОНОВЛЕННЯ

Добре, я розгадав другий крок. Ось нова скрипка, що показує прогрес: https://jsfiddle.net/retrogradeMT/9pffnmjp/

Оскільки я використовую Vue-маршрутизатор, я не використовую реквізит для надсилання даних до нового компонента. Натомість мені потрібно встановити параметри на v-link, а потім використовувати перехідний гачок, щоб прийняти його.

Зміни V-link див. Названі маршрути в документах vue-router :

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

Потім на компоненті додайте дані до параметрів маршруту, див. Перехідні гачки :

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

Відповіді:


46

------------- Наведене нижче стосується лише Vue 1 --------------

Передача даних може здійснюватися різними способами. Спосіб залежить від типу використання.


Якщо ви хочете передавати дані з вашого html під час додавання нового компонента. Це робиться за допомогою реквізиту.

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

Це значення властивості буде доступне для вашого компонента лише в тому випадку, якщо ви додасте ім'я prop-nameдо свого propsатрибута.


Коли дані передаються від компонента до іншого компоненту через якусь динамічну або статичну подію. Це робиться за допомогою диспетчерів подій та мовників. Так, наприклад, якщо у вас є така структура компонентів:

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

І ви хочете надіслати дані з <my-child-A>до, <my-child-B>тоді <my-child-A>вам доведеться відправити подію:

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

Ця подія пройде весь батьківський ланцюг. І від того, у кого з батьків у вас є відділення, <my-child-B>ви транслюєте подію разом із даними. Отже, у батьків:

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

Тепер ця трансляція пройде по дитячому ланцюжку. І в будь-якій дитині ви хочете взяти подію, в нашому випадку<my-child-B> ми додамо ще одну подію:

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

Третім способом передачі даних є параметри у v-посиланнях. Цей метод застосовується, коли ланцюги компонентів повністю зруйновані або у випадках, коли URI змінюється. І я бачу, ви вже їх розумієте.


Визначтесь, який тип передачі даних ви хочете, і виберіть відповідним чином.


1
Дякую, це було дуже корисно. Єдиний шматок, з яким я досі борюся, - це правила іменування. тобто: у мене є user.name, яке я передаю через v-link як ім’я. Тепер я можу редагувати змінну імені та передавати її назад оригінальному компоненту як ім’я, але оригінальний компонент не має змінної з іменем. Чого мені тут не вистачає? Не здається можливим передати об’єкт через v-link?
ретроград

1
Ви вже передаєте об’єкт. paramsє об’єктом. Клавіші імені можна призначити this.user.nameваш компонент. Створіть скрипку, якщо вам потрібна допомога, і дайте мені знати. Перевірте це: vuejs.github.io/vue-router/en/route.html
notANerdDev

Ах, добре, зараз у мене це. Знову дякую. Я вдячний за вашу допомогу, це справді набагато зрозуміліше.
ретроград

6
Чудова відповідь, але, наскільки я розумію, вона не буде працювати з 2.0, оскільки події застаріли?
rix

2
Мені сподобалась відповідь, але потім я дійшов до коментарів, і оскільки я працюю з Vue 2, я відчуваю, що не зможу запропонувати другий метод. Це правильно побоюватися?
Конрад Вільтерстен

23

Найкращий спосіб надіслати дані з батьківського компонента дитині - використання реквізиту .

Передача даних від батьків до дитини через props

  • Заявити props(масив або об'єкт ) у дочірній структурі
  • Передайте дитині <child :name="variableOnParent">

Див. Демо нижче:

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>


невелике виправлення: "<child-comp" замість "<child" і variableAtParent .. Передати його дитині через <child-comp: name = "variableAtParent">
muenalan

Це буде працювати лише з простими властивостями, посилання на об'єкти не оновлюватимуться. Наприклад, якщо у вас є батьківська властивість be array, і цей масив замінено в батьківському об’єкті на інший масив, дочірній елемент його не побачить.
Стен Соколов

@StanSokolov зовсім не. Я працюю для масивів, див .: jsfiddle.net/acdcjunior/q4mank05 . Якщо масив не реактивний, ви, мабуть, стикаєтесь із проблемою реактивності. Спробуйте скористатись Vue.set, докладніше тут: vuejs.org/v2/guide/reactivity.html#For-Arrays
acdcjunior

Який сенс, якщо він не реагує? Звичайно, він реагував, посилання постійно замінювалося новим масивом. Vue не поширює "зміни посилань" на дітей, лише змінює значення на простих елементах. Отже, якщо посилання на масив було переписано у батьківському режимі, діти все одно побачать старе посилання. Ніколи не дізнаюсь, що батько зараз працює з іншим об’єктом.
Стен Соколов

@StanSokolov Дивіться це: jsfiddle.net/acdcjunior/ftmrne2h масив замінюється на батьківський і дитина бачить / реагує на нього (натисніть кнопку для тестування). Або ти маєш на увазі щось інше? Якщо так, було б корисно, якщо ви відредагуєте скрипку, щоб показати її
acdcjunior

15

Я думаю, що проблема тут:

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

Коли ви ставите префікс до prop, :ви вказуєте Vue, що це змінна, а не рядок. Тож {{}}навколо вам не потрібно user.name. Спробуйте:

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

РЕДАГУВАТИ -----

Вищесказане відповідає дійсності, але головна проблема тут полягає в тому, що при зміні URL-адреси та переході на новий маршрут оригінальний компонент зникає. Для того, щоб другий компонент редагував батьківські дані, другий компонент повинен бути дочірнім компонентом першого або просто частиною того самого компонента.


Спасибі Джефе. Я намагався вилучити {{}}, але все одно отримую ті самі помилки.
ретроград

2

Я знайшов спосіб передати батьківські дані до області компонентів у Vue, я думаю, це трохи зламано, але, можливо, це допоможе вам.

1) Довідкові дані у екземплярі Vue як зовнішній об’єкт (data : dataObj)

2) Тоді у функції повернення даних у дочірньому компоненті просто поверніть parentScope = dataObjі вуаля. Тепер ти не можеш робити такі речі, як {{ parentScope.prop }}і будеш працювати як шарм.

Щасти!


Це поєднує обидва компоненти разом, що може бути добре для дерева та його вузлів, але зазвичай це не надає переваги. Я би намагався цього уникнути.
грудень

1

Вищезгадані відповіді працюють добре, але якщо ви хочете передавати дані між двома компонентами односемейних братів, тоді можна також використовувати шину подій. Перегляньте цей блог, який допоможе вам краще зрозуміти.

припустимо для 2 компонентів: CompA & CompB, що мають однакові батьківські та main.js для налаштування основної програми vue. Для передачі даних з CompA до CompB без залучення батьківського компонента ви можете зробити наступне.

у файлі main.js оголосіть окремий глобальний екземпляр Vue, який буде шиною подій.

export const bus = new Vue();

У CompA, де генерується подія: вам потрібно передати подію на шину.

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

Тепер завдання - прослухати випущену подію, тому в CompB ви можете слухати як.

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

Переваги:

  • Менший і чистий код.
  • Батько не повинен брати участь у передачі даних з одного дочірнього комп’ютера на інший (із збільшенням кількості дітей їх буде важко підтримувати)
  • Дотримується підходу pub-sub.

0

Я отримую доступ до основних властивостей за допомогою $root.

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

-2

Глобальна змінна JS (об'єкт) може використовуватися для передачі даних між компонентами. Приклад: Передача даних з Ammlogin.vue до Options.vue. У Ammlogin.vue rspData встановлюється як відповідь сервера. У Options.vue відповідь сервера надається через 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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.