如何在元素不可见时更新Vue的ref元素并实现焦点切换?
Vue切换单选后聚焦新表单元素的实现方案
当然可以实现,不需要手动修改ref指向新元素(反而不推荐这么做),更可靠的方式是给不同表单元素绑定独立ref,或者用动态ref结合监听来自动聚焦新元素。下面是两种实用方案:
方案一:独立Ref + 监听切换
给每个表单元素绑定专属ref,监听单选按钮的选中值变化,切换后调用对应元素的focus()方法:
<template> <div> <label> <input type="radio" v-model="selectedType" value="input" /> 输入框 </label> <label> <input type="radio" v-model="selectedType" value="select" /> 下拉框 </label> <input v-if="selectedType === 'input'" ref="inputRef" type="text" placeholder="输入内容" /> <select v-else ref="selectRef"> <option value="1">选项1</option> <option value="2">选项2</option> </select> </div> </template> <script setup> import { ref, watch, onMounted } from 'vue' const selectedType = ref('input') const inputRef = ref(null) const selectRef = ref(null) // 挂载时聚焦默认输入框 onMounted(() => { inputRef.value?.focus() }) // 监听单选值变化,切换焦点 watch(selectedType, (newType) => { if (newType === 'select') { selectRef.value?.focus() } else { inputRef.value?.focus() } }) </script>
这个方案逻辑清晰,每个元素的ref独立管理,不容易出错,适合表单元素不多的场景。
方案二:动态Ref + NextTick
如果表单元素较多,可以用动态ref把当前显示的元素统一存到一个变量里,再结合nextTick确保DOM更新后聚焦:
<template> <div> <label> <input type="radio" v-model="selectedType" value="input" /> 输入框 </label> <label> <input type="radio" v-model="selectedType" value="select" /> 下拉框 </label> <input v-if="selectedType === 'input'" :ref="el => el && (currentActiveEl = el)" type="text" placeholder="输入内容" /> <select v-else :ref="el => el && (currentActiveEl = el)"> <option value="1">选项1</option> <option value="2">选项2</option> </select> </div> </template> <script setup> import { ref, watch, onMounted, nextTick } from 'vue' const selectedType = ref('input') let currentActiveEl = null onMounted(() => { currentActiveEl?.focus() }) watch(selectedType, async () => { // 等待v-if切换完成,DOM更新后再聚焦 await nextTick() currentActiveEl?.focus() }) </script>
注意事项
- 不要手动修改ref的
value属性指向其他元素(比如inputRef.value = selectRef.value),Vue会自动维护ref与DOM元素的绑定关系,手动赋值会破坏这个机制。 - 用
?.可选链操作符避免元素未渲染时调用focus()报错。 - 切换元素时必须用
nextTick等待DOM更新完成,否则可能获取不到新渲染的元素。
内容的提问来源于stack exchange,提问作者gespinha
相关产品推荐
相关产品推荐

