Vue向数组添加新元素后页面不重新渲染问题求助
问题根源
你当前的问题出在深度监听tempForm的watch逻辑:每次tempForm内部任何数据变化(包括点击按钮给options数组添加元素),watch的handler都会执行。而handler里只要当前question的type是select,就会把question.options重新赋值为[""],直接覆盖了你刚添加的新元素,导致v-for渲染的输入框看起来没更新——实际上是数组被重置了。
另外,addItems里用this.$set给数组加元素完全没必要,Vue原生就能检测数组的push操作。
修复方案
1. 重构watch逻辑,只监听type变化
不要监听整个tempForm的所有变化,而是只在question的type切换时才初始化或删除options。最直接的方式是给每个question单独添加type的监听:
初始化第一个question的监听
在created钩子中给第一个question加监听:
created() { const firstQ = this.tempForm.tempQuestions[0]; this.$watch(() => firstQ.type, (newType) => { if (newType === 'select') { firstQ.options = [""]; } else { delete firstQ.options; } }, { immediate: true }); }
新增question时自动加监听
修改addQuestion方法,给每个新创建的question添加上type监听:
addQuestion() { const newQ = { question: null, description: null, type: null, }; this.tempForm.tempQuestions.push(newQ); // 给新question绑定type监听 this.$watch(() => newQ.type, (newType) => { if (newType === 'select') { newQ.options = [""]; } else { delete newQ.options; } }, { immediate: true }); this.questions++; }
这样只有当下拉框切换类型时才会处理options,修改数组元素时不会触发重置。
2. 简化addItems方法
直接用数组push添加元素,Vue能自动检测到这个变化并更新视图:
addItems() { this.tempForm.tempQuestions[0].options.push(""); }
3. 给v-for添加key(推荐)
为了让Vue更高效地更新列表,给循环的.option元素加上唯一key:
.option(v-for="(option, index) in tempForm.tempQuestions[0].options" :key="index") input(type="text" placeholder="Option" v-model="tempForm.tempQuestions[0].options[index]")
完整修复后的代码
模板(Pug)
.formHolder .quest input(type="text" placeholder="Question" v-model="tempForm.tempQuestions[0].question") input(type="text" placeholder="Description" v-model="tempForm.tempQuestions[0].description") select(name="category" v-model="tempForm.tempQuestions[0].type") option(value="text") text option(value="select") Dropdown option(value="number") Number .option(v-for="(option, index) in tempForm.tempQuestions[0].options" :key="index") input(type="text" placeholder="Option" v-model="tempForm.tempQuestions[0].options[index]") button(v-if="tempForm.tempQuestions[0].type === 'select'" @click="addItems") Add Options
脚本
import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "HomeView", components: { HelloWorld, }, data() { return { questions: 0, tempForm: { tempQuestions: [ { question: null, description: null, type: null, }, ], }, form: { questions: [], }, }; }, created() { // 初始化第一个问题的类型监听 const firstQ = this.tempForm.tempQuestions[0]; this.$watch(() => firstQ.type, (newType) => { if (newType === 'select') { firstQ.options = [""]; } else { delete firstQ.options; } }, { immediate: true }); }, methods: { addQuestion() { const newQ = { question: null, description: null, type: null, }; this.tempForm.tempQuestions.push(newQ); // 给新问题绑定类型监听 this.$watch(() => newQ.type, (newType) => { if (newType === 'select') { newQ.options = [""]; } else { delete newQ.options; } }, { immediate: true }); this.questions++; }, addItems() { this.tempForm.tempQuestions[0].options.push(""); }, }, };
内容的提问来源于stack exchange,提问作者Abdullah Ibn Shahin
相关产品推荐
相关产品推荐

