Как получить данные v-модели из дочернего компонента Vue 2?

Я сделал пользовательский компонент ввода и хочу получить данные из него в родительском компоненте. Сначала я использовал компонент так, как написано в гайде:

Input.vue

<input
      :value = "value"
      @input = "$emit('input', $event.target.value)"
      class = "w-full border-[1px] bg-transparent p-4 lg:text-sm placeholder:text-[#97999B]"
      :placeholder = "placeholder"
      :class = "statusStyles"
    />

MyComponent.vue

    <Input
          placeholder = "Phone number"
          type = "text"
          v-model = "phone"
        />

Все заработало, но я разбил этот код на компоненты и появилась еще одна обертка, она выглядит так:

Form.vue

<OrderFormInfo
      v-if = "step === 'info'"
      :name = "name"
      :apart = "apart"
      :city = "city"
      :phone = "phone"
      :postal = "postal"
      :region = "region"
      :address = "address"
      @next-step = "handleNext"
    />

OrderInfo.vue

        <Input
          placeholder = "phone number"
          type = "text"
          v-model = "phone"
        />
        <Input
          placeholder = "recipient name"
          type = "text"  
          v-model = "name"
        />

Input.vue

<template>
  <div class = "w-full space-y-[10px]">
    <input
      :value = "value"
      @input = "$emit('input', $event.target.value)"
      class = "w-full border-[1px] bg-transparent p-4 lg:text-sm placeholder:text-[#97999B]"
      :placeholder = "placeholder"
      :class = "statusStyles"
    />
    <p v-if = "errorStatus" class = "text-red-500">{{ errors[0] }}</p>
  </div>
</template>

<script>
export default {
  props: {
    errors: Array,
    sucess: Boolean,
    value: String,
    errorStatus: Boolean,
    placeholder: String,
  },
  computed: {
    statusStyles() {
      if (this.errorStatus) {
        return "border-red-500 text-red-500";
      }
      if (!this.errorStatus && this.value.length > 3) {
        return "bg-white border-black text-black";
      }
      return "text-black  border-[#97999B]";
    },
  },
};
</script>

Как получить данные из OrderInfo.vue в Form.vue? Я пытался передать данные через реквизит, но vue выдает ошибку, что вы не можете этого сделать. Я не понимаю, как использовать v-модель с вложенными компонентами

Обычно вы можете и должны передавать данные через реквизит. Может ли быть так, что в ошибке указано, что вы пытались настроить эти реквизиты? Вы должны скопировать эти реквизиты в объекты данных, если это так :)

Wimanicesir 10.02.2023 11:37

Ошибка, которую вы получили, говорит о том, что вы не должны изменять значение свойства напрямую через дочерний компонент. Чтобы решить эту проблему, вы должны использовать emits в OrderInfo.vue.

Amini 10.02.2023 12:08

@Amini Я не понимаю, как это сделать, мне нужно получить данные в Form.vue через $emit?

Dmitry Staver 10.02.2023 12:15

Событие Do and Emit в OrderInfo, получение от него значений и использование в Form.vue

Amini 10.02.2023 12:23
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
54
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете наблюдать за реквизитом, используя функцию наблюдателя в вашем родительском (Form.vue) компоненте внутри хука mounted.

Вам нужно просто прикрепить ref к самому верхнему дочернему компоненту. Например:

<order-form-info :name = "name" :phone = "phone" ref = "orderFormComponent"></order-form-info>

Живая демонстрация:

Vue.component('orderFormInfo', {
  props: ['name', 'phone'],
  template: `<div>
    <input-field
      placeholder = "phone number"
      type = "text"
      v-model = "phone"/>
    <input-field
      placeholder = "recipient name"
      type = "text"
      v-model = "name"/>
  </div>`
});

Vue.component('inputField', {
  props: ['value', 'placeholder'],
  template: `<input
:value = "value"
@input = "$emit('input', $event.target.value)"
:placeholder = "placeholder"
/>`
});

var app = new Vue({
  el: '#form',
  data: {
    name: 'Alpha',
    phone: '1111111111'
  },
  mounted() {
    this.$watch(
      "$refs.orderFormComponent.phone", (newVal, oldVal) => {
         console.info(newVal, oldVal)
      }
    );
  }
});
<script src = "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id = "form">
  <order-form-info :name = "name" :phone = "phone" ref = "orderFormComponent"></order-form-info>
</div>
Ответ принят как подходящий

Я смог решить это таким образом, я нашел статью в Интернете. Вот изменения:

OrderFormInfo.vue

     <Input
          placeholder = "Phone number"
          type = "text"
          :error-status = "false"
          :errors = "[]"
          :value = "phone"
          @input = "$emit('input-phone', $event)"
     />

OrderForm.vue

  <OrderFormInfo.
      v-if = "step === 'info'"
      :name = "name"
      @input-name = "name = $event"
      :phone = "phone"
      @input-phone = "phone = $event"
      @next-step = "handleNext"
  />

Есть несколько способов сделать это. Например-

  1. Использование шины событий (для отправки события при обновлении данных).
  2. Использование Vuex (для обновления состояния и доступа к нему в любом месте)

Приведенные выше два решения требовали некоторой установки. Самый простой способ — использовать this.$root.$emit для передачи события любому компоненту без использования какой-либо глобальной переменной, шины или реквизита.

Вот рабочая демонстрация. Попробуйте изменить значения телефона и имени в поле ввода (OrderFormInfo.vue), и вы должны увидеть изменения в Form.vue (родительский компонент).

Vue.component('orderFormInfo', {
  props: ['prop_name', 'prop_phone'],
  data() {
    return {
      name: this.prop_name,
      phone: this.prop_phone,
    }
  },
  watch: {
    name(newVal, oldVal) {
      this.$root.$emit('onNameUpdate', newVal);
    },
    phone(newVal, oldVal) {
      this.$root.$emit('onPhoneUpdate', newVal);
    }
  },
  template: `<div>
    <b>OrderFormInfo.vue</b><br>
    <input-field
      placeholder = "phone number"
      type = "text"
      v-model = "phone"/>
    <input-field
      placeholder = "recipient name"
      type = "text"
      v-model = "name"/>
  </div>`
});

Vue.component('inputField', {
  props: ['value', 'placeholder'],
  template: `<input
:value = "value"
@input = "$emit('input', $event.target.value)"
:placeholder = "placeholder"
/>`
});

var app = new Vue({
  el: '#app',
  data() {
    return {
      name: 'My Name',
      phone: '9090909090'
    }
  },
  created() { 
    this.$root.$on('onNameUpdate', (name) => {
      this.name = name;
    });
    this.$root.$on('onPhoneUpdate', (phone) => {
      this.phone = phone;
    })
  }
});
<script src = "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id = "app">
  <b>Form.vue</b><br>
  Name - {{ name }} <br>
  Phone - {{ phone }} <br><br>
  <order-form-info :prop_name = "name" :prop_phone = "phone"></order-form-info>
  
</div>

Важно-
Когда вы передаете реквизиты из Form.vue в OrderFormInfo.vue, не пытайтесь изменить этот реквизит напрямую. Сначала скопируйте свойства в переменную данных и измените их. Читайте причину здесь.

Другие вопросы по теме