Получить данные из одного компонента Vue в другом компоненте?

Я использую Vue.js 2.5.13 и имею такую ​​структуру:

component-one.vue:

    <template>
      <div>
        <input type="text" v-model="input_one">
        <component-two></component-two>
      </div>
    </template>

    <script>
      import ComponentTwo from 'component-two.vue'

      export default {
        name: "component-one",
        components: {
          ComponentTwo
        },
        data() {
          return {
            input_one: 'Hello from ComponentOne',
            input_two: ... // <-- I want to get value from ComponentTwo input_two (v-model) here
          }
        }
      }
    </script>

component-two.vue:

    <template>
      <div>
        <input type="text" v-model="input_two">
      </div>
    </template>

    <script>
      export default {
        name: "component-two",
        data() {
          return {
            input_one: 'Hello from ComponentTwo'
          }
        }
      }
    </script>

Как получить данные из ComponentTwo в компоненте ComponentOne? Это важно для меня, потому что у меня много похожих компонентов с полями (огромная форма на сайте регистрации) и я понятия не имею о вызове данных между Vue-компонентами ..


person koddr    schedule 29.01.2018    source источник
comment
Возможный дубликат Обмен данными между различными компонентами в Vuejs   -  person Roy J    schedule 29.01.2018
comment
@RoyJ - я не думаю, что я буду ссылаться на этот вариант как на возможный дубликат, поскольку в этом ответе предлагается использовать модификатор .sync, который имеет удален из vue. Но, конечно же, есть много других существующих вопросов, на которые провайдер отвечает в этой ситуации.   -  person PatrickSteele    schedule 29.01.2018


Ответы (5)


Этого легко добиться с помощью глобальной шины событий.

https://alligator.io/vuejs/global-event-bus/

Для более крупных и сложных приложений я бы рекомендовал использовать инструмент управления состоянием, такой как vuex.

https://vuex.vuejs.org/en/

person Community    schedule 29.01.2018

Vuejs использует "реквизиты" для общения между родителями и детьми и "испускает" события для общения между детьми и родителями.

введите описание изображения здесь

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

component-one.vue:

    <template>
      <div>
        <input type="text" v-model="input_one">
        <component-two
            @CustomEventInputChanged="doSomenthing">
        </component-two>
      </div>
    </template>

    <script>
      import ComponentTwo from 'component-two.vue'

      export default {
        name: "component-one",
        components: {
          ComponentTwo
        },
        data() {
          return {
            input_one: 'Hello from ComponentOne',
            input_two: ''
          }
        },
        methods: {
            doSomenthing ( data ) {
                this.input_two = data;
            }
        }
      }
    </script>

component-two.vue:

    <template>
      <div>
        <input type="text" v-model="input_two" @change="emitEventChanged>
      </div>
    </template>

    <script>
      export default {
        name: "component-two",
        data() {
          return {
            input_one: 'Hello from ComponentTwo'
          }
        },
        methods: {
            emitEventChanged () {
                this.$emit('CustomEventInputChanged', this.input_two);
            }
        }

      }
    </script>

Это должно работать

person Luca Giardina    schedule 29.01.2018

Вам необходимо реализовать систему, которая отправляет v-модель обратно родителю.

Это можно сделать, используя вычисляемое свойство внутри component-two, которое испускает изменение внутри своего метода set.

Пример:

Vue.component('component-two', {
  name: 'component-two',
  template: '#component-two-template',
  props: {
    value: {
      required: true,
      type: String,
    },
  },
  computed: {
    message: {
      get() {
        return this.value;
      },
      set(val) {
        this.$emit('input', val);
      },
    },
  },
});

var app = new Vue({
  el: '#app',
  data: {
    message1: 'm1',
    message2: 'm2',
  },
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script type="text/x-template" id="component-two-template">
  <input type="text" v-model="message"/>
</script>
<div id="app">
  <input type="text" v-model="message1"/>
  <component-two v-model="message2"></component-two>
  <p>Output</p>
  <pre>{{message1}}</pre>
  <pre>{{message2}}</pre>
</div>

person Ferrybig    schedule 29.01.2018

Есть несколько способов сделать это, и некоторые из них упоминаются в других ответах:
(в произвольном порядке, подробнее читайте в разделах ниже)

  1. Используйте глобальную шину событий
  2. Используйте свойства для компонентов
  3. Используйте атрибут v-модели
  4. Используйте модификатор синхронизации
  5. Используйте Vuex.

Что касается двусторонней привязки, имейте в виду, что она может вызвать цепочку мутаций, которые трудно поддерживать, цитируется из документации:

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

Вот некоторые подробности доступных методов:

1.) Используйте глобальную шину событий

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

2.) Используйте опоры для компонентов

Реквизиты просты в использовании и являются идеальным способом решения наиболее распространенных проблем.
Благодаря как Vue наблюдает за изменениями: все свойства должны быть доступны для объекта, иначе они не будут реагировать. Если какие-либо свойства добавляются после того, как Vue завершил работу над ними, 'set' должен будет использоваться.

 //Normal usage
 Vue.set(aVariable, 'aNewProp', 42);
 //This is how to use it in Nuxt
 this.$set(this.historyEntry, 'date', new Date());

Объект будет реактивным как для компонента, так и для родителя:

Если вы передадите объект / массив в качестве опоры, это будет двусторонняя синхронизация автоматически - измените данные в дочернем элементе, они будут изменены в родительском.

Если вы передаете простые значения (строки, числа) через реквизиты, вы должны явно использовать . модификатор синхронизации

Как указано в -> https://stackoverflow.com/a/35723888/1087372

3.) Используйте атрибут v-model

Атрибут v-model - это синтаксический сахар, который обеспечивает простую двустороннюю привязку между родительским и дочерним объектами. Он делает то же самое, что и модификатор синхронизации, только он использует определенную опору и определенное событие для привязки.

Этот:

 <input v-model="searchText">

то же самое, что и это:

 <input
   v-bind:value="searchText"
   v-on:input="searchText = $event.target.value"
 >

Где свойство должно быть значением, а событие должно быть входом

4.) Используйте модификатор синхронизации.

Модификатор sync также является синтаксическим сахаром и делает то же самое, что и v-model, только имена свойств и событий устанавливаются тем, что используется.

В родительском его можно использовать следующим образом:

 <text-document v-bind:title.sync="doc.title"></text-document>

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

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

5.) Используйте Vuex

Vuex - это хранилище данных, доступное из каждого компонента. На изменения можно подписаться.

Используя хранилище Vuex, легче увидеть поток мутаций данных, и они явно определены. Используя инструменты разработчика vue, можно легко отлаживать и откатывать сделанные изменения.

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

См. руководство по началу работы

person SanBen    schedule 30.04.2020

Вы можете использовать .sync Modifier.

<template>
  <div>
    <input type="text" v-model="input_one">
    <component-two :secondValue.sync="input_two"></component-two>
  </div>
</template>

<script>
  import ComponentTwo from 'component-two.vue'

  export default {
    name: "component-one",
    components: {
      ComponentTwo
    },
    data() {
      return {
        input_one: 'Hello from ComponentOne',
        input_two: ''
      }
    }
  }
</script>

компонент-два.vue:

<template>
  <div>
    <input type="text" v-model="input_two">
  </div>
</template>

<script>
  export default {
    name: "component-two",
    data() {
      return {
        input_one: 'Hello from ComponentTwo',
        input_two: ''
      },
      watch: {
        input_two : function(val){
          this.$emit('update:secondValue', val)
        }
      }
    }
  }
</script>
person El Danielo    schedule 29.01.2018