Vue的AutoComplete组件输入后下拉列表无法自动聚焦怎么办?

Tr° 林莹 阅读 12

大家好,我在用Vue写AutoComplete组件时遇到个怪问题。当用户输入”ne”后,虽然下拉列表显示了结果,但焦点没有自动定位到第一个选项。我试过在input事件里用querySelector获取第一个li元素调用focus(),但控制台报错”Cannot read property ‘focus’ of null”。


<template>
  <div>
    <input v-model="query" @input="handleInput">
    <ul v-if="results.length">
      <li v-for="(item, index) in results" :key="index">{{ item }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      query: '',
      results: []
    }
  },
  methods: {
    handleInput() {
      // 模拟异步搜索
      setTimeout(() => {
        this.results = ['Neil', 'Nemo', 'Nancy']
        document.querySelector('.suggestion li:first-child')?.focus()
      }, 200)
    }
  }
}
</script>

后来发现是DOM还没渲染完成就执行了聚焦操作,但改用nextTick包裹后还是不行。有人知道正确的自动聚焦实现方式吗?

我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
宇文丽珍
这个问题的关键在于DOM更新和异步操作的时机没对齐,你用nextTick是对的,但可能没处理完整。建议直接在nextTick里确保元素存在再调用focus,而且别忘了给li加tabindex属性,否则它没法聚焦。

先改模板部分,把tabindex加上去,顺便给ul加个类名方便选择:
<template>
<div>
<input v-model="query" @input="handleInput">
<ul v-if="results.length" class="suggestions">
<li v-for="(item, index) in results" :key="index" :tabindex="index">{{ item }}</li>
</ul>
</div>
</template>


然后在脚本里这样写:
<script>
export default {
data() {
return {
query: '',
results: []
}
},
methods: {
handleInput() {
// 模拟异步搜索
setTimeout(() => {
this.results = ['Neil', 'Nemo', 'Nancy']
this.$nextTick(() => {
const firstItem = document.querySelector('.suggestions li:first-child')
if (firstItem) {
firstItem.focus()
} else {
console.warn('无法找到第一个选项,检查渲染逻辑')
}
})
}, 200)
}
}
}
</script>


这里有几个点要注意:第一是tabindex必须加上,不然li默认不是可聚焦元素;第二是$nextTick确实能等DOM更新完,但你还得判断一下元素是不是真的存在,防止意外情况;第三是querySelector的选择器要准确,我这边用了.suggestions li:first-child,比你原来的更明确。

说实话这种问题挺常见的,尤其是涉及到异步和DOM操作的时候,建议以后遇到类似问题可以先打个断点看看元素到底渲染出来没有,能省不少时间。
点赞 3
2026-02-17 12:03