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

