You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 18:06:03