删除子组件后Vue列表渲染异常:仅最后一项被移除问题求助
问题描述
我将对象列表加载到子组件的v-for循环中,每个子组件配有删除按钮可移除选中项。目标子项已从数据列表中正确删除,但页面渲染时仅最后一个子组件被移除,不清楚问题所在。
- 初始状态:页面显示多条带选择框、输入框和删除按钮的子组件行
- 删除后异常:点击中间行的删除按钮,数据列表中对应项已删除,但页面仅最后一行消失,中间行仍保留
父组件代码
<tbody> <route-form-row v-for="(route, index) in form.current_routes" :key="index" :organizations="organizations" :route="route" :index="index" :completed="form.completed" @onUpdateOrganization="updateCurrentRouteOrganization" @onUpdateNumberOfRoutes="updateCurrentRouteNumberOfRoutes" @onRemoveRoute="removeCurrentRoute" ></route-form-row> </tbody>
删除逻辑
removeCurrentRoute(index) { this.form.current_routes.splice(index, 1); }
子组件代码
<template> <tr> <td> <select v-model="organization" :class="['form-select', {'is-invalid': organizationError}]" @change.prevent="updateOrganization()"> <option value="">------</option> <option v-for="org in organizations" :key="org.id" :value="org" :selected="organization.id === org.id">{{ org.name }}</option> </select> <div v-for="error of this.v$.organization.$errors" :key="error.$uid" :class="[{'invalid-feedback': organizationError}]">{{ error.$message }}</div> </td> <td class="col-2"> <input type="number" v-model="number_of_routes" :class="['form-control', {'is-invalid': numberOfRoutesError}]" step="1" min="0" @keyup="updateNumberOfRoutes"> <div v-for="error of this.v$.number_of_routes.$errors" :key="error.$uid" :class="[{'invalid-feedback': numberOfRoutesError}]">{{ error.$message }}</div> </td> <td class="text-end"> <div> <a href="#" @click.prevent="removeRoute()"> <font-awesome-icon :icon="['far', 'trash-can']" /> </a> </div> </td> </tr> </template> <script> import { useVuelidate } from '@vuelidate/core' import { requiredIf, helpers, minValue } from "@vuelidate/validators" export default { name: 'RouteFormRow', props: { index: Number, route: Object, organizations: Array, completed: Boolean }, setup() { return { v$: useVuelidate() }; }, data() { return { organization: this.route.organization, number_of_routes: this.route.number_of_routes, } }, validations() { return { organization: { required: helpers.withMessage('Ce champ est obligatoire', requiredIf(this.completed)) }, number_of_routes: { required: helpers.withMessage('Ce champ est obligatoire', requiredIf(this.completed)), minValue: helpers.withMessage('Assurez-vous que cette valeur est supérieure ou égale à 0.', minValue(0)), } } }, computed: { organizationError () {return this.v$.organization.$errors.length > 0}, numberOfRoutesError () {return this.v$.number_of_routes.$errors.length > 0}, }, methods: { updateOrganization() { this.$emit('onUpdateOrganization', this.index, this.organization); }, updateNumberOfRoutes() { this.$emit('onUpdateNumberOfRoutes', this.index, this.number_of_routes) }, removeRoute() { this.$emit('onRemoveRoute', this.index); } } } </script>
问题原因与修复方案
核心原因
key使用错误:用数组索引作为v-for的key时,删除中间项后,后续项的索引会自动前移。Vue会复用现有组件实例,仅更新props,导致本该删除的组件未被销毁,反而最后一个因索引失效被移除。- 子组件数据脱节:子组件
data中的organization和number_of_routes仅在初始化时赋值,未监听routeprop的变化,导致数据更新不同步。
修复步骤
1. 改用唯一标识作为v-for的key
将父组件中:key="index"改为route的唯一ID(如route.id),确保每个子组件身份唯一,Vue能正确识别需要删除的组件:
<tbody> <route-form-row v-for="(route, index) in form.current_routes" :key="route.id" <!-- 替换为route的唯一标识 --> :organizations="organizations" :route="route" :index="index" :completed="form.completed" @onUpdateOrganization="updateCurrentRouteOrganization" @onUpdateNumberOfRoutes="updateCurrentRouteNumberOfRoutes" @onRemoveRoute="removeCurrentRoute" ></route-form-row> </tbody>
2. 让子组件数据响应props变化
通过watch监听route prop的变化,同步更新子组件本地数据:
// 子组件script中添加watch watch: { route: { deep: true, handler(newRoute) { this.organization = newRoute.organization; this.number_of_routes = newRoute.number_of_routes; } } }
或更推荐使用计算属性实现双向绑定,直接关联父组件数据:
// 子组件script中替换data和methods部分 computed: { localOrganization: { get() { return this.route.organization; }, set(val) { this.$emit('onUpdateOrganization', this.index, val); } }, localNumberOfRoutes: { get() { return this.route.number_of_routes; }, set(val) { this.$emit('onUpdateNumberOfRoutes', this.index, val); } } }
同时修改模板中的v-model:
<select v-model="localOrganization" ...>...</select> <input type="number" v-model="localNumberOfRoutes" ...>
3. 可选:确保数据响应式
如果form.current_routes是嵌套对象,需保证其本身是Vue响应式数据(Vue2用Vue.set,Vue3用ref/reactive),避免修改后页面不更新。
内容的提问来源于stack exchange,提问作者Kornikopic
相关产品推荐
相关产品推荐

