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

Vue.js动态表单如何获取所有字段值并存入Firebase实时数据库

问题根因

无法获取动态表单字段值的核心原因有3个:

  • 混用Vue两种组件写法:<script setup>组合式API和普通选项式<script>块的状态默认不互通,存储步骤值的stepNumbers定义在选项式script的data中,<script setup>里的提交逻辑根本访问不到这个变量
  • 新增字段逻辑属性名不匹配:初始步骤项结构是{step: ""},但addField方法推入数组的是{value: ""},和v-model绑定的input.step字段不对应,新增输入框的值无法被正确收集
  • 提交到Firebase的逻辑中没有配置steps字段,即便拿到步骤值也不会存入数据库
修复方案

统一使用<script setup>组合式API编写所有逻辑,不要拆分两个script块。

第一步:迁移动态表单状态和增删方法到setup脚本

删除原有的选项式<script>块,在<script setup>中补充步骤相关的响应式变量和方法,同时在提交逻辑中加入步骤字段的处理:

<script setup>
import { database, auth } from "../firebase";
import { ref, setWithPriority, push, set } from "firebase/database";
import { ref as reference } from "vue";
import router from "../router";

let exerciseRef = ref(database, "exercises/");
let selected = reference(null);
// 迁移步骤数组为setup内响应式变量
const stepNumbers = reference([{ step: "" }]);

// 迁移增删字段方法
const addField = () => {
  // 推入的对象属性和v-model绑定字段保持一致
  stepNumbers.value.push({ step: "" });
};
const removeField = (index) => {
  if (stepNumbers.value.length <= 1) return;
  stepNumbers.value.splice(index, 1);
};

const props = defineProps([
    "selected",
    "name",
    "video",
    "summary",
    "description",
    "isActive",
]);

const emits = defineEmits([
    "update:name",
    "update:video",
    "update:description",
    "update:summary",
    "update:isActive",
]);

function createExercise() {
    // 提取有效步骤值,过滤空输入
    const steps = stepNumbers.value.map(item => item.step).filter(Boolean);
    
    exerciseRef = ref(database, `exercises/${selected.value - 1}/4`);

    set(exerciseRef, {
        name: props.name,
        video: props.video,
        summary: props.summary,
        description: props.description,
        isActive: props.isActive,
        // 加入步骤字段
        steps: steps
    });

    let logRef = ref(database, "logs/exercise/");
    let pushRef = push(logRef);

    setWithPriority(
        pushRef,
        {
            type: "toegevoegd",
            exercise: props.name,
            admin: auth.currentUser.displayName,
            date: new Date().toLocaleString("nl-NL"),
        },
        0 - Date.now()
    );

    router.push("/admin/exercises");
}
</script setup>

第二步:修正模板中的事件绑定

去掉多余的传参,调整后的表单代码如下:

<form>
    <div class="form-group">
        <label>Stappen</label>
        <div
            v-for="(input, index) in stepNumbers"
            :key="`stepInput-${index}`"
            class="input wrapper flex items-center"
        >
            <input
                v-model="input.step"
                type="text"
                class="h-10 rounded-lg outline-none p-2"
                placeholder="Voer stap in"
            />
            <!-- 新增按钮直接调用方法,不需要传参 -->
            <svg
                @click="addField"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                width="24"
                height="24"
                class="ml-2 cursor-pointer"
            >
                <path fill="none" d="M0 0h24v24H0z" />
                <path
                    fill="green"
                    d="M11 11V7h2v4h4v2h-4v4h-2v-4H7v-2h4zm1 11C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16z"
                />
            </svg>

            <!-- 删除按钮只需要传入当前索引 -->
            <svg
                v-show="stepNumbers.length > 1"
                @click="removeField(index)"
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                width="24"
                height="24"
                class="ml-2 cursor-pointer"
            >
                <path fill="none" d="M0 0h24v24H0z" />
                <path
                    fill="#EC4899"
                    d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z"
                />
            </svg>
        </div>
    </div>
    <!-- 提交按钮加.prevent阻止表单默认刷新行为 -->
    <button type="submit" @click.prevent="createExercise" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded">
        提交练习
    </button>
</form>

注意事项

  • 新手阶段不要在同一个单文件组件中混写两种API的script块,很容易出现状态不互通的问题,统一用一种写法即可
  • v-model绑定的字段名必须和数组内对象的属性名完全一致,否则会出现输入不生效、值收集失败的问题
  • 提交前建议增加表单校验逻辑,比如练习名称不能为空、步骤内容不能为空等,避免存入无效数据到Firebase

内容的提问来源于stack exchange,提问作者luca.04

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:36:18