Vuejs компонент ваппера, связывающий несколько значений - PullRequest
2 голосов
/ 31 января 2020

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

Я не могу понять, как связать текстовое поле Freeform с родительским полем, а также параметр, выбранный пользователем. Я не уверен, как передать изменения / ввод.

Пытаясь следовать этому из Пользовательские документы Документы

Простой пример здесь:

Edit vuejs-select-freeform

InputWrapper:

<template v-if="inputType === 'text'">
  <input type="text" v-bind:value="value" v-bind="$attrs" v-on="inputListeners">
</template>
<template v-else-if="inputType === 'select'">
  <select v-bind="$attrs" v-bind:value="value" v-on="inputListeners">
    <option value>Select</option>
    <option
      v-for="option in options"
      v-bind:value="option.Id"
      v-bind:key="option.Id"
    >{{option.Description}}</option>
  </select>
  <!--Only show the input if it's a "FreeformOption"-->
  <!--How do I make this update the parent??-->
  <input
    type="text"
    v-if="selectedOption.IsFreeformOption"
    v-bind:value.sync="freeformValue"
    v-bind="$attrs"
    v-on:update="$emit('update:person.ExactIncome', '111')"
    v-on:input="$emit('input:person.ExactIncome', '222')"
  >

  <!--Would ideally recursively call the InputWrapper component
   <InputWrapper
    inputType="text"
    v-if="selectedOption.IsFreeformOption"
    v-bind:value= "freeformValue"
    v-on:input="$emit('input', $event)"
    ></InputWrapper>
  -->
</template>

Демонстрация:

<InputWrapper
  id="incomeLevels"
  inputType="select"
  :options="incomeLevels"
  :freeformValue.sync="person.ExactIncome"
  v-model="person.IncomeLevelID"
></InputWrapper>

Рабочая демонстрация:

Обертывание freeformValue в вычисляется и выдается изменение там.

wrappedFreeform: {
      get() {
        return this.freeformValue;
      },
      set(v) {
        this.$emit("update:freeformValue", v);
      }
    }

Edit vuejs-select-freeform

Ответы [ 2 ]

3 голосов
/ 31 января 2020

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

// InputWrapper
<input
  v-model="freeformValue" 
  >
// Demo
<InputWrapper
  :freeformValue.sync="person.ExactIncome"
></InputWrapper>

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

// InputWrapper
<input
  v-model="freeformValue.ExactIncome" 
  >
// Demo
<InputWrapper
  :freeformValue.sync="person" //pass an object here
></InputWrapper>

Решение, предложенное @MisterIsaak, более удобно:

// InputWrapper
<input
  v-model="wrappedFreeform" 
  >

computed: {
  wrappedFreeform: {
      get() {
        return this.freeformValue; // here we just get the value
      },
      set(v) {
        this.$emit("update:freeformValue", v); // emmit an event instead of mutating the prop directly
      }
    }
}


// Demo
<InputWrapper
  :freeformValue.sync="person.ExactIncome" //the value will be updated properly
></InputWrapper>

2 голосов
/ 31 января 2020

Emit - это ссылка на одну функцию в родительском компоненте

, в вашем случае вход будет

<input
        type="text"
        v-if="selectedOption.IsFreeformOption"
        :value="freeformValue"
        @input="$emit('updateFreeFormValue', $event.target.value)"
      >

, а в вашем родительском

<InputWrapper
      id="incomeLevels"
      inputType="select"
      :options="incomeLevels"
      :freeformValue.sync="person.ExactIncome"
      v-model="person.IncomeLevelID"
      @updateFreeFormValue="updateFreeFormValue"
    ></InputWrapper>

и ваши методы

methods: {
    updateFreeFormValue(value){
      this.person.ExactIncome = value;
    }
  },
...