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
相关产品推荐
相关产品推荐

