You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js中v-for循环内自定义输入组件无法获取全部输入值的问题排查

问题分析与解决方案

嘿,我一眼就看出问题所在啦——你在循环渲染自定义Input组件时,所有组件都绑定到了同一个formInput变量上!这就意味着每一个输入框的内容变化都会覆盖掉之前的值,最后自然只能拿到最后一个输入框的内容咯。咱们来一步步修复:

1. 父组件:改用对象存储多输入框的值

你需要把formInput从单个值改成一个对象,这样每个输入框可以通过它的name属性作为键,来存储对应的值。修改后的父组件代码如下:

<template>
  <div class="form container">
    <form v-on:submit.prevent="sendMail" method="post" class="d-flex row shadow bg-dark border-right border-dark">
      <h3 class="col-12">Contact me</h3>
      <!-- 把v-model绑定到formInput的对应name属性上 -->
      <Input 
        v-model="formInput[input.name]" 
        v-for="input in inputs" 
        v-bind:key="input.name" 
        :label="input.label" 
        :multiple="input.multiple" 
        :type="input.type" 
        :name="input.name" 
        :class="input.classes" 
        :required="input.required"
      ></Input>
    </form>
  </div>
</template>
<script>
import Input from "../components/Input";
export default {
  name: "Contact",
  components: {Input},
  data() {
    return {
      // 改成空对象,后续会根据输入框name自动添加属性
      formInput: {},
    }
  },
  methods: {
    sendMail () {
      console.log(this.formInput);
      // 现在这里会输出所有输入框的键值对,比如 {username: 'xxx', email: 'xxx'}
    }
  }
}
</script>

2. 子组件:优化双向绑定的实现(可选但更规范)

你的子组件目前是自己维护inputVal状态再emit事件,其实Vue的v-model是语法糖,更规范的做法是直接接收value prop,然后在输入变化时emitinput事件。这样子组件不需要自己维护状态,更符合组件设计的单一职责:

<template>
  <div class="form-input">
    <label :for="name" v-if="label && type !='submit' ">{{label}} <span v-if="required">*</span></label>
    <a v-if="multiple" href="#" class="btn">Upload</a>
    <input 
      :value="value" 
      @input="$emit('input', $event.target.value)"
      :multiple="multiple" 
      v-if="type != 'textarea' && type != 'submit'" 
      class="form-control" 
      :required="required" 
      :class="classes" 
      :type="type" 
      :name="name" 
      :placeholder="placeHolder"
    >
    <textarea 
      :value="value" 
      @input="$emit('input', $event.target.value)"
      :multiple="multiple" 
      v-else-if="type != 'submit'" 
      class="form-control" 
      :required="required" 
      :class="classes" 
      :name="name" 
      :placeholder="placeHolder"
    ></textarea>
    <button :multiple="multiple" :name="name" v-else type="submit">{{label}}</button>
  </div>
</template>
<script>
export default {
  name: "Input",
  props: {
    // 新增value prop,接收父组件传递的值
    value: [String, Number, Boolean],
    // 别忘了你原来的其他props哦:label, multiple, type, name, classes, required, placeHolder
    label: String,
    multiple: Boolean,
    type: String,
    name: String,
    classes: String,
    required: Boolean,
    placeHolder: String
  }
}
</script>

为什么这样改?

  • 父组件用对象存储值:每个输入框通过唯一的name属性对应对象里的一个键,这样不同输入框的值就不会互相覆盖了,提交时formInput里会包含所有输入框的内容。
  • 子组件用value prop:这是Vue自定义组件实现v-model的标准方式,子组件只负责渲染和传递事件,状态交给父组件管理,逻辑更清晰,也避免了子组件内部状态和父组件不同步的问题。

现在再点击提交按钮,你就能拿到所有输入框的值啦!

内容的提问来源于stack exchange,提问作者Ari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 08:47:34