Vue删除动态生成表单行时UI与数据更新不一致如何解决
问题根因
出现UI和数据错位的核心原因是v-for的key设置完全不符合Vue虚拟DOM diff规则:
- 当前使用
randomSalt + index作为key,其中randomSalt是每次组件重渲染都会生成新值的随机数,index会在数组调用splice删除元素后随元素位置变化而改变,两者都属于不稳定标识,无法作为虚拟节点的匹配依据。 - 当删除中间行时,后续元素的index整体前移,Vue会错误复用旧位置的组件实例,导致数据已经更新,但组件仍显示被删位置的旧内容,也就是你看到的错位现象。如果强制全量更换key触发重渲染,又会因为所有节点被判定为全新节点销毁重建,直接丢失输入框已填内容。
- 另外
chainCondition方法存在索引取值bug:数组长度为n时最后一项索引是n-1,当前取this.customFormData[this.customFormData.length]永远拿到undefined,会导致新增行初始值异常。
修复方案
- 给
customFormData中每一行配置项绑定全局唯一、终身不变的id,id和行数据强绑定,不随数组位置变化改变。 - 把
v-for的key替换为每一项自身的稳定id,删除无用的randomSalt计算属性和salt字段,避免key随机变动导致的全量重渲染。 - 修复新增行时的索引取值错误。
核心修复代码
JS部分调整
export default { components: { EditableValue }, data () { return { customFormData: [ { id: Symbol(), // 初始化首行时生成唯一id type: 'if', schema: Schema } ] } }, methods: { deleteCondition (index) { this.customFormData.splice(index, 1) }, chainCondition (type) { // 修复最后一项索引取值错误 const lastConfig = this.customFormData[this.customFormData.length - 1] this.customFormData.push({ ...lastConfig, id: Symbol(), // 新增行生成独立的唯一id type, schema: this.schema }) } } }
模板部分调整
<template v-slot:custom-form> <el-row v-for="(condition, index) of customFormData" type="flex" :key="condition.id" <!-- 替换为行数据自带的稳定id --> class="condition row-bg" :justify="isElse(condition) ? 'start' : 'space-around'" > <!-- 其余模板内容保持不变 --> </el-row> </template>
原理说明
Vue虚拟DOM diff过程中,会通过key判断两个渲染位置的节点是否为同一个。使用稳定id作为key时,无论数组怎么增删排序,每一行的key始终和自身数据、组件实例绑定,Vue可以精准匹配对应节点,只删除真正被移除的行组件,其余行的组件实例和输入状态都会被正确保留,不会出现错位或输入内容丢失的问题。
内容的提问来源于stack exchange,提问作者Cacious
相关产品推荐
相关产品推荐

