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

Nuxt3+FormKit表单问题:如何将配料存入单一数组?

解决FormKit动态配料表单生成数组结构的问题

问题概述

使用Nuxt 3开发应用,通过FormKit处理表单,在newrecipe页面中用NewIngredientInput组件动态添加配料行,需要将所有配料存储为数组格式以符合API要求,但当前表单输出的是form_2、form_8这类独立对象,无法形成期望的数组结构。

期望与当前输出对比

期望的JSON结构

{
  "name": "data",
  "ingredients": [
    {
      "amount": "1",
      "unit": "data",
      "name": "data"
    },
    {
      "amount": "2",
      "unit": "data",
      "name": "data"
    }
  ],
  "description": "data",
  "region": "data",
  "keywords": "data",
  "photo": [
    {
      "name": "1.jpg",
      "file": "[object File]"
    }
  ]
}

当前错误的JSON结构

{
  "name": "data",
  "form_2": {
    "amount": "1",
    "unit": "data",
    "name": "data"
  },
  "description": "data",
  "region": "data",
  "keywords": "data",
  "photo": [
    {
      "name": "1.jpg",
      "file": "[object File]"
    }
  ],
  "form_8": {
    "amount": "2",
    "unit": "data",
    "name": "data"
  }
}

修复步骤

1. 修改NewIngredientInput.vue组件

问题根源在于每个配料组件内部嵌套了FormKit type="form",导致FormKit为每个子表单生成独立的键。需要移除内部表单,改用字段名的数组语法绑定到父表单:

<template>
  <div class="newIngridient">
    <FormKit
      v-model="row.amount"
      type="number"
      :name="`ingredients[${index}].amount`"
      label="Cantidad"
      validation="required"
    />
    <FormKit
      v-model="row.unit_measure"
      type="text"
      :name="`ingredients[${index}].unit`"
      label="Unidad"
      validation="required"
    />
    <div class="ingredient">
      <FormKit
        v-model="row.name"
        type="text"
        :name="`ingredients[${index}].name`"
        label="Ingrediente"
        validation="required"
      />
    </div>
    <button class="remove" @click="removeRow" v-show="showRemoveButton">
      -
    </button>
  </div>
</template>

<script>
export default {
  props: {
    showRemoveButton: {
      type: Boolean,
      default: false,
    },
    row: {
      type: Object,
      required: true,
    },
    index: {
      type: Number,
      required: true,
    },
  },
  methods: {
    removeRow() {
      this.$emit("removeRow");
    },
  },
};
</script>

2. 修改newrecipe.vue页面

调整组件调用方式,传递row和index,并修正表单提交逻辑:

<template>
  <div class="container">
    <UserMenu />
    <SideNavUser />
    <div class="new-recipe-container">
      <div class="title">Crear Receta</div>
      <div class="form">
        <FormKit type="form" @submit="createRecipe" #default="{ value }">
          <FormKit
            type="text"
            name="name"
            label="Título de la Receta"
            validation="required"
          />
          <div
            class="new-ingredient"
            v-for="(row, index) in inputRows"
            :key="index"
          >
            <NewIngredientInput
              :row="row"
              :index="index"
              :showRemoveButton="index > 0"
              @removeRow="removeRow(index)"
            />
          </div>
          <button @click="addRow" class="add">+</button>
          
          <FormKit
            type="textarea"
            rows="10"
            name="description"
            label="Instrucciones"
            placeholder="Escribe oraciones o párrafos."
            validation="required"
          />
          <div class="triple">
            <FormKit
              type="text"
              name="region"
              label="Región"
              validation="required"
            />
            <FormKit
              type="text"
              name="keywords"
              label="Palabras Clave"
              placeholder="pollo, ajo, ..."
              help="Ingresa palabras claves separadas por comas."
              validation="required"
            />
            <div class="photo">
              <FormKit
                type="file"
                name="photo"
                accept=".jpg,.png"
                label="Imagen"
                help="Solo puedes incluir imagenes con extensión .jpg o .png"
                validation="required"
              />
            </div>
          </div>
          <FormKit type="submit" label="Crear" />
          <pre wrap>{{ value }}</pre>
        </FormKit>
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";

export default {
  data() {
    return {
      inputRows: [{ amount: "", unit_measure: "", name: "" }],
    };
  },
  methods: {
    addRow() {
      this.inputRows.push({ amount: "", unit_measure: "", name: "" });
    },
    removeRow(index) {
      this.inputRows.splice(index, 1);
    },

    async createRecipe({ value }) {
      const recipeForm = {
        ...value,
        ingredients: value.ingredients.map(ing => ({
          amount: ing.amount,
          unit: ing.unit,
          name: ing.name
        }))
      };

      try {
        const photoForm = new FormData();
        photoForm.append("photo", value.photo.files[0]);
        const imageResponse = await axios.post(
          "API endpoint for photo",
          photoForm,
          { headers: { "Content-Type": "multipart/form-data" } }
        );

        recipeForm.photo = imageResponse.data;

        const recipeResponse = await axios.post(
          "API endpoint for all the recipe data",
          recipeForm
        );

        console.log("Receta creada exitosamente: ", recipeResponse.data);
      } catch (error) {
        console.error("Error creating recipe:", error.message);
      }
    },
  },
};
</script>

关键修复点说明

  • 移除NewIngredientInput内部的FormKit type="form",改用ingredients[${index}].field的命名方式,让FormKit识别这是数组字段。
  • 调整添加按钮的位置,避免每个配料行重复生成添加按钮。
  • 提交表单时直接使用FormKit提供的value参数,无需手动从inputRows映射,同时为图片上传请求添加正确的Content-Type头。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 03:47:13