Vue 3 v-for绑定的template refs未同步DOM状态,删除条目后无法触发input聚焦
根本原因
Vue 3 中v-for配合数组类型的模板ref的设计逻辑是:每次DOM更新完成后,将当前渲染出来的所有对应DOM元素追加到ref数组中,不会主动清空之前残留的旧DOM引用。你看到的删除科目后ref数组长度不变、存在过期引用,就是这个特性导致的。
手动修改这个ref数组是完全安全的,没有额外隐患,Vue官方没有限制用户对该数组的读写操作。
最优解决方案:用ID映射存储ref
不要依赖数组下标对应DOM引用,改用对象以科目ID为键存储对应input的引用,完全规避数组增删带来的下标错位问题:
模板代码
<template> <!-- 注意v-for必须绑定唯一key,这里直接用科目id即可 --> <div v-for="subject in subjects" :key="subject.id"> <input v-model="subject.id" <!-- 用函数式ref绑定,将DOM存入对应id的键下 --> :ref="el => { if (el) subjectRefMap[subject.id] = el }" @change="handleIdEdit(subject)" /> <input v-model="subject.name" /> </div> </template>
逻辑代码
import { ref, nextTick } from 'vue' // 原科目数组 const subjects = ref([]) // 改用对象存储ref,key为科目唯一id const subjectRefMap = ref({}) // 编辑id触发查重逻辑的示例 const handleIdEdit = (currentSubject) => { const duplicateIndex = subjects.value.findIndex(item => item.id === currentSubject.id && item !== currentSubject ) if (duplicateIndex > -1) { // 删除重复的原有条目 subjects.value.splice(duplicateIndex, 1) // 直接通过id获取当前编辑的input,直接聚焦 nextTick(() => { subjectRefMap.value[currentSubject.id]?.focus() }) } }
如果你要继续使用数组类型ref
如果不想改现有逻辑,只需要在组件每次更新前清空ref数组即可,Vue会在渲染完成后自动填充当前真实存在的DOM引用:
import { ref, onBeforeUpdate } from 'vue' const subjectRefs = ref([]) // 组件更新前清空旧的ref数组 onBeforeUpdate(() => { subjectRefs.value = [] })
这样就能保证subjectRefs的长度、下标永远和subjects数组完全对应。
内容的提问来源于stack exchange,提问作者grindarius
相关产品推荐
相关产品推荐

