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

Vue.js通过ref获取input元素调用focus报错解决方法

问题原因
  • 核心报错原因:你通过this.$refs[ref]拿到的是原生<input>DOM元素,不是自定义Vue组件实例,只有Vue组件实例上才有$el属性,原生DOM元素本身就自带focus()方法,你多加了一层$el调用,自然会拿到undefined。
  • 之前试$nextTick没生效的原因也很简单:这不是DOM渲染时机的问题,是属性访问路径写错了,等多久都不会存在$el属性。
  • 现有代码还有几个隐藏问题:
    • 三个输入框都加了autofocus属性,页面加载时只有最后一个输入框会自动获得焦点,前两个的autofocus完全无效
    • 内联写的原生oninput事件里的this指向DOM元素本身,虽然当前跳转逻辑碰巧能跑,但不符合Vue的写法规范,后续加逻辑很容易出上下文错误
    • 手动重复写3个输入框的逻辑冗余度太高,后续要改6位/4位验证码要重复改很多代码
    • 现在删除跳转的逻辑没有判断当前输入框是否为空,只要按delete就跳,会导致输入框有内容时,用户按删除键删完内容直接跳走,不符合正常交互预期

解决方法

最小改动修复(不用调整现有组件结构)

直接把handleDeleteClick里的$el去掉即可,同时补充空值判断避免交互异常:

handleDeleteClick(prevRef, currentValueKey) {
  // 只有当前输入框为空时,按删除才跳转到前一个输入框
  if (this[currentValueKey] === '') {
    this.$refs[prevRef].focus()
  }
}

对应模板里的事件绑定同步调整传参:

  • n2输入框的删除事件改成@keyup.delete="handleDeleteClick('n1', 'i2')"
  • n3输入框的删除事件改成@keyup.delete="handleDeleteClick('n2', 'i3')"

优化重构方案(易维护,支持任意长度验证码)

建议把重复的输入框用v-for循环渲染,去掉冗余的重复代码,同时把内联的input事件抽成Vue方法,去掉多余的无效autofocus,修正后完整代码如下:

<template>
  <div :class="onwhite ? 'on-white' : ''">
    <input
      v-for="(item, index) in codeLength"
      :key="index"
      :ref="`n${index+1}`"
      v-model="codeList[index]"
      class="input-two-fa center"
      type="number"
      :disabled="disabled"
      min="0"
      max="9"
      autocomplete="off"
      :autofocus="index === 0"
      @input="handleInput(index)"
      @keyup.delete="handleDelete(index)"
    >
  </div>
</template>

<script>
import { validate2fa } from "~/helpers/frontValidator";
export default {
  name: "InputTwoFa",
  props: {
    disabled: {
      type: Boolean,
      default: false
    },
    onwhite: {
      type: Boolean,
      default: false
    },
    // 支持自定义验证码位数,默认3位做演示
    codeLength: {
      type: Number,
      default: 3
    }
  },
  data() {
    return {
      codeList: Array(this.codeLength).fill('')
    }
  },
  watch: {
    codeList: {
      deep: true,
      handler(val) {
        this.$emit('returnTwoFa', val)
      }
    }
  },
  methods: {
    handleInput(index) {
      // 过滤非法输入
      this.codeList[index] = validate2fa(this.codeList[index])
      // 输入有效内容后自动跳转到下一个输入框,最后一个输入框不跳转
      if (this.codeList[index] !== '' && index < this.codeLength - 1) {
        // v-for绑定的ref返回值是数组,取[0]拿到对应DOM
        this.$refs[`n${index+2}`][0].focus()
      }
    },
    handleDelete(index) {
      // 当前输入框为空且不是第一个输入框时,跳转到前一个输入框
      if (this.codeList[index] === '' && index > 0) {
        this.$refs[`n${index}`][0].focus()
      }
    }
  }
}
</script>

注意:用v-for循环生成ref时,this.$refs.xxx拿到的是DOM元素数组,所以要取[0]才能拿到对应的input元素,这是循环渲染ref时的常见坑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:33:38