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

92

Я изо всех сил пытаюсь понять, как передавать данные между компонентами в vue.js. Я прочитал документацию несколько раз и просмотрел множество вопросов и руководств по vue, но все еще не понимаю.

Чтобы понять это, я надеюсь на помощь в завершении довольно простого примера.

  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-router, я не использую реквизиты для отправки данных в новый компонент. Вместо этого мне нужно установить параметры для v-ссылки, а затем использовать перехватчик перехода, чтобы принять его.

Изменения 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. И я вижу, вы их уже понимаете.


Решите, какой тип передачи данных вы хотите, и выберите соответствующий вариант.

notANerdDev
источник
1
Спасибо, это было действительно полезно. Единственная вещь, с которой я все еще борюсь, - это соглашения об именах. то есть: у меня есть user.name, которое я передаю через v-ссылку в качестве имени. Теперь я могу отредактировать переменную name и передать ее исходному компоненту как name, но исходный компонент не имеет переменной с именем name. Что мне здесь не хватает? Не представляется возможным передать объект через v-ссылку?
ретроград
1
Вы уже передаете объект. paramsэто объект. Ключ имени может быть назначен this.user.nameв вашем компоненте. Создайте скрипку, если вам нужна помощь, и дайте мне знать. Проверьте это: vuejs.github.io/vue-router/en/route.html
notANerdDev 01
А, хорошо, теперь у меня есть. Еще раз спасибо. Я ценю вашу помощь, это действительно многое прояснило.
ретроград
6
Отличный ответ, но, насколько я понимаю, он не будет работать с 2.0, поскольку события устарели?
rix 08
2
Мне понравился ответ, но затем я перешел к комментариям, и, поскольку я работаю с Vue 2, я чувствую, что у меня не будет второго метода, предложенного вами. Это правильно опасается?
Конрад Вильтерстен
23

Лучший способ отправить данные от родительского компонента к дочернему - использовать props .

Передача данных от родителя к потомку через 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>

acdcjunior
источник
небольшое исправление: «<child-comp» вместо «<child» и variableAtParent .. Передайте его дочернему
элементу
Он будет работать только с простым свойством, ссылки на объекты не будут обновляться. Например, если у вас родительским свойством является массив, и этот массив был заменен в родительском объекте на другой массив, дочерний элемент его не увидит.
Стан Соколов
@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}}">

Когда вы добавляете в опору префикс, :вы указываете Vue, что это переменная, а не строка. Так что вам не нужно {{}}окружающее user.name. Пытаться:

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

РЕДАКТИРОВАТЬ-----

Сказанное выше верно, но большая проблема здесь в том, что при изменении URL-адреса и переходе на новый маршрут исходный компонент исчезает. Чтобы второй компонент редактировал родительские данные, второй компонент должен быть дочерним компонентом первого или просто частью того же компонента.

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

Я нашел способ передать родительские данные в область видимости компонента во Vue, я думаю, что это немного похоже на взлом, но, возможно, это поможет вам.

1) Справочные данные в экземпляре Vue как внешний объект (data : dataObj)

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

Удачи!

Лукас Серена
источник
Это соединение обоих компонентов вместе, что может быть хорошо для дерева и его узлов, но обычно не приветствуется. Я бы постарался этого избежать.
Декабрь
1

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

Предположим для двух компонентов: 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>
Kjelle J
источник