如何在Vue的v-for循环中通过v-model收集多组训练数据并存入数组
如何用v-model实现训练动作每组的重量和次数输入并存储
看起来你卡在上游数据结构和v-model绑定的对应关系上了——原有的exercisesInput结构太简单,没法匹配「多个训练动作+每个动作多组数据」的场景。我来一步步帮你解决这个问题:
1. 先重构输入数据的结构
首先我们需要让存储输入数据的数组和你的训练动作数组结构完全对应,这样才能精准绑定每组的输入项。在组件初始化时生成这个结构(以Vue3为例,Vue2写法我放在后面):
import { ref } from 'vue' const exercises = [ { id: 1, name: 'exercise1', sets: 3 }, { id:2, name: 'exercise2', sets: 2 }, { id:3, name: 'exercise3', sets: 4 } ] // 初始化输入存储数组:每个动作对应其组数的空输入项 const exercisesInput = ref(exercises.map(exercise => ({ exerciseId: exercise.id, exerciseName: exercise.name, sets: Array(exercise.sets).fill().map((_, idx) => ({ setNumber: idx + 1, // 显示用的组号(1、2、3...) reps: '', weight: '', completed: false // 标记该组是否已完成 })) })))
2. 调整模板的v-for和v-model绑定
现在可以把输入框和exercisesInput里的对应项绑定了,注意用索引关联动作和组的对应关系:
<template> <div class="exercise-container"> <!-- 遍历每个训练动作 --> <div v-for="(exercise, exerciseIdx) in exercises" :key="exercise.id"> <h4>{{ exercise.name }}</h4> <!-- 遍历当前动作的所有组 --> <div class="set-item" v-for="(_, setIdx) in exercise.sets" :key="`${exercise.id}-set-${setIdx+1}`"> <span>第 {{ setIdx + 1 }} 组</span> <input type="number" placeholder="重量" v-model="exercisesInput[exerciseIdx].sets[setIdx].weight" > <input type="number" placeholder="次数" v-model="exercisesInput[exerciseIdx].sets[setIdx].reps" > <button @click="markSetComplete(exerciseIdx, setIdx)" :disabled="exercisesInput[exerciseIdx].sets[setIdx].completed" > {{ exercisesInput[exerciseIdx].sets[setIdx].completed ? '已完成' : '标记完成' }} </button> </div> </div> <!-- 可选:添加按钮查看已输入的数据 --> <button @click="logInputData">查看已存储的数据</button> </div> </template>
3. 实现标记完成的函数
这个函数用来标记当前组为完成状态,因为v-model是双向绑定,用户输入的重量和次数已经实时同步到exercisesInput里了:
const markSetComplete = (exerciseIdx, setIdx) => { // 标记该组为完成 exercisesInput.value[exerciseIdx].sets[setIdx].completed = true; // 如果需要把完成的组单独提取到另一个数组,也可以在这里处理: // const finishedSet = { ...exercisesInput.value[exerciseIdx].sets[setIdx] }; // completedSets.value.push(finishedSet); } const logInputData = () => { console.log('已输入的训练数据:', exercisesInput.value); }
Vue2 适配写法
如果你用的是Vue2,只需要把响应式数据和初始化逻辑放到data和created里:
export default { data() { return { exercises: [ { id: 1, name: 'exercise1', sets: 3 }, { id:2, name: 'exercise2', sets: 2 }, { id:3, name: 'exercise3', sets: 4 } ], exercisesInput: [] } }, created() { this.exercisesInput = this.exercises.map(exercise => ({ exerciseId: exercise.id, exerciseName: exercise.name, sets: Array(exercise.sets).fill().map((_, idx) => ({ setNumber: idx + 1, reps: '', weight: '', completed: false })) })) }, methods: { markSetComplete(exerciseIdx, setIdx) { this.exercisesInput[exerciseIdx].sets[setIdx].completed = true; }, logInputData() { console.log('已输入的训练数据:', this.exercisesInput); } } }
核心思路总结
- 结构对应:让输入存储数组的结构和训练动作数组完全匹配,每个动作的每组数据都能找到对应的输入项,这是v-model能精准绑定的关键。
- 唯一key:用
${exercise.id}-set-${setIdx+1}作为每组的key,避免Vue的diff算法出现渲染错误。 - 实时同步:v-model会自动把用户输入同步到
exercisesInput,点击「标记完成」只是修改状态,不需要手动push数据。
内容的提问来源于stack exchange,提问作者Frederik
相关产品推荐
相关产品推荐

