Vue 3 - Путаница с V-моделью

Я учусь сама vue 3. Я читаю статью за статьей о v-model и каждый раз, когда я думаю, что понимаю, как это работает, я снова путаюсь.

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

Дочерний компонент.vue

  <div>
    <select
      :value = "modelValue"
      @input = "$emit('update:modelValue', $event.target.value)"
    >
      <option v-for = "option in options" :key = "option">
        {{ option }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  props: ["options", "modelValue"],

  emits: ["update:modelValue"],

  methods: {
    selected() {

//??????
//want to emit this to the parent
      let selectedIndex = this.$event.target.selectedIndex + 1
      //this.$emit(value, selectedIndex)
    },
  },
};
</script>

родитель.vue

<template>
  <my-drop-down :options = "options" v-model = "selectedOption" />
 
</template>

<script>
import myDropDown from "./components/base_dropdown.vue";

export default {
  name: "App",

  data: () => ({
    selectedOption: "2 Line",
    selectedIndex: 0,
    options: ["1 Line", "2 Line", "3 Line"],
  }),

  components: {
    myDropDown,
  },

  methods: {
    //How can I call this when the select value changes??
    onSelectChange(selected, index) {
      console.info(`Parent L3rd Change, name: ${selected}, index: ${index} `);
    },

  },
};
</script>

Двусторонняя привязка работает корректно. Я могу контролировать значение выпадающего списка либо из дочернего, либо из родительского элементов. Но как мне вызвать метод onSelectChange в моем дочернем компоненте

Кроме того, и это может быть глупый вопрос, но...

v-model = "selectedOption" это то же самое, что написать :value = "modelValue" @input = "$emit('update:modelValue', $event.target.value)"

так почему родитель так пишется <my-drop-down :v-model = "selectedOption" />

а ребенок так написал <select :value = "modelValue" @input = "$emit('update:modelValue', $event.target.value)">

и не просто <select :v-model = "selectedOption />

Поведение ключевого слова "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) для оценки ваших знаний,...
0
0
48
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Согласно Раздел Vuejs API о Наблюдателях:

Computed properties allow us to declaratively compute derived values. However, there are cases where we need to perform "side effects" in reaction to state changes - for example, mutating the DOM, or changing another piece of state based on the result of an async operation.

With Options API, we can use the watch option to trigger a function whenever a reactive property changes.

Итак, для вашего кода это может выглядеть примерно так:

  watch: {
    selectedOption(newValue, oldValue) {
      console.info('In watcher. New value: ' + newValue)
      
      // get the index of the String in the array and use it to set
      // the selectedIndex:
      this.selectedIndex = this.options.findIndex(i => i === newValue) + 1;
      console.info('selectedIndex: ' + this.selectedIndex)
    }
  },

Что касается "второй части" вашего вопроса,

why is the parent written like this <my-drop-down :v-model = "selectedOption" />

and the child written like this <select :value = "modelValue" @input = "$emit('update:modelValue', $event.target.value)">

and not simply <select :v-model = "selectedOption />

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

Ответ принят как подходящий

Если вы хотите вызвать метод внутри вашего родительского компонента при «изменении значения выбора», лучше вызвать его внутри Vue смотреть, как показано ниже:

Parent component:

<template>
  <my-drop-down :options = "options" v-model = "selectedOption" />
</template>

<script>
import myDropDown from "../components/baseDropdown.vue";
export default {
  name: "parentModel",
  data: () => ({
    selectedOption: "2 Line",
    // selectedIndex: 0,
    options: ["1 Line", "2 Line", "3 Line"],
  }),

  components: {
    myDropDown,
  },

  computed: {
    /* It is better to use computed property for "selectedIndex", because it is related to "selectedOption" and changes accordingly. */
    selectedIndex: function () {
      return this.options.indexOf(this.selectedOption)
    }
  },

  watch: {
    selectedOption(newSelect, oldSelect) {
      this.onSelectChange(this.selectedOption, this.selectedIndex)
    }
  },

  methods: {
    //How can I call this when the select value changes??
    onSelectChange(selected, index) {
      console.info(`Parent L3rd Change, name: ${selected}, index: ${index} `);
    },

  },
}
</script>

<style scoped>

</style>

Child component:

<template>
  <div>
    <select
        :value = "modelValue"
        @change = "$emit('update:modelValue', $event.target.value)"
    >
      <!-- You can use v-model also here. But it only changes the value of "modelValue" and does not emit anything to parent component. -->
<!--    <select v-model = "modelValue">-->
      <option v-for = "option in options" :key = "option">
        {{ option }}
      </option>
    </select>
  </div>
</template>

<script>
export default {
  name: "baseDropdown",
  props: ["options", "modelValue"],

  emits: ["update:modelValue"],

  /* --------------------------------- */
  /* You don't need this method, because "$emit('update:modelValue', $event.target.value)" that is used in "select" tag itself is enough to emit data to the parent component. */
  /* --------------------------------- */

//   methods: {
//     selected() {
//
// //??????
// //want to emit this to the parent
//       let selectedIndex = this.$event.target.selectedIndex + 1
//       //this.$emit(value, selectedIndex)
//     },
//   },
}
</script>

<style scoped>

</style>

А по поводу второй части вашего вопроса:

v-model = "selectedOption" is the same as writing :value = "modelValue" @input = "$emit('update:modelValue', $event.target.value)"

На мой взгляд, это неверное утверждение по двум причинам:

  1. Причина первая: согласно Vue-документы:

v-model = "selectedOption" is the same as writing :value = "selectedOption" @input = "event => selectedOption = event.target.value"

вы не видите никаких $emit в приведенном выше заявлении. Но в вашем случае вы хотите передать данные родительскому компоненту.

  1. Причина вторая: опять же согласно Vue-документы лучше использовать change as an event вместо тега <select>.

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