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

Vue3组合式API中如何在v-for循环里用模板引用移动焦点?

问题

使用按钮显示/隐藏列表项,希望点击按钮时通过ref聚焦到第一个“额外显示”的项(第6个,对应索引5)。在Vue选项式API中可以正常实现,但组合式API里报错:Uncaught TypeError: Cannot read properties of undefined (reading 'value')。Vue开发者工具中可见listItem是包含12个元素的Ref数组,但点击按钮时就是无法正确引用目标元素。

已尝试操作:

  • 在showFullList中尝试listItem[5].value.focus()和listItem.value[5].focus()两种写法
  • 在onMounted()中打印listItem和listItem.value[5]到控制台

原代码:

<script setup>
import { ref } from 'vue'

const listItem = ref([])
const showAllCounties = ref(false)

const showhideItems = (index) => {
  if (!showAllCounties.value) {
    return index < 5
  } else {
    return true
  }
}

const showFullList = () => {

  document.activeElement.blur()
  showAllCounties.value = !showAllCounties.value
if (listItem) {
  console.log('yes') // returns 'yes'
console.dir(listItem) // shows proxy array with all 12 items
}

  const target = listItem[5]
  if (target) {
    target.value.focus()
    console.log('yes, ' +target)
   } else {
    console.log('no')
  }

  listItem[5].value.focus()

//also tried listItem.value[5].focus()

}

</script>


<template>
<ul>
 <li
  v-for="(county, index) in project.data.counties"
  v-show="showhideItems(index)"
  class="project-counties-list"
  ref="listItem"
  :key="county.id"
   >
  {{ county.county_name }}, {{ index }}
 </li>
</ul>
 <button type="button" @click="showFullList">{{ ButtonText }}</button>
</template>
解决方案

核心问题

  1. DOM更新滞后:修改showAllCounties.value后,Vue不会立刻更新DOM,此时第6个<li>还处于隐藏状态,DOM元素未完成渲染/显示,直接调用focus()会找不到有效元素。
  2. Ref数组访问错误:组合式API中,v-for绑定的ref数组,正确访问路径是listItem.value[index]——listItem是Ref对象,.value才是存储DOM元素的数组,数组内每一项直接是DOM元素,不需要再取.value。

修复步骤

  1. 用nextTick()等待DOM更新完成后再执行聚焦,确保目标<li>已显示。
  2. 修正Ref数组访问方式,直接通过listItem.value[5]获取DOM元素并调用focus()。
  3. 增加元素存在性判断,避免报错。

修正后代码

<script setup>
import { ref, nextTick } from 'vue'

const listItem = ref([])
const showAllCounties = ref(false)

const showhideItems = (index) => {
  return !showAllCounties.value ? index < 5 : true
}

const showFullList = async () => {
  document.activeElement.blur()
  showAllCounties.value = !showAllCounties.value

  // 等待DOM更新完成
  await nextTick()

  const target = listItem.value[5]
  if (target) {
    target.focus()
    console.log('聚焦成功')
  } else {
    console.log('目标元素不存在')
  }
}
</script>

<template>
<ul>
 <li
  v-for="(county, index) in project.data.counties"
  v-show="showhideItems(index)"
  class="project-counties-list"
  ref="listItem"
  :key="county.id"
 >
  {{ county.county_name }}, {{ index }}
 </li>
</ul>
<button type="button" @click="showFullList">{{ showAllCounties ? '收起列表' : '显示全部' }}</button>
</template>

补充说明

  • nextTick()会在DOM更新周期结束后执行回调,保证操作的是最新DOM状态。
  • v-for绑定ref时,Vue会自动把所有匹配的DOM元素存入listItem.value数组,数组顺序和v-for循环顺序一致。
  • 如果列表项是异步加载的,需确保数据加载完成后再访问ref数组,可结合onMounted()或数据加载后的回调处理。

内容的提问来源于stack exchange,提问作者buckthorn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 19:22:25