AlpineJS升级到v3后OTP输入框代码报Cannot read 'focus' of undefined错误
错误原因
这个报错是AlpineJS v2到v3的$refs机制不兼容导致的:
Alpine v2支持动态绑定:x-ref属性,你用:x-ref="index"会将对应输入框以数字index为键注册到$refs对象,所以$refs[0]能取到第一个输入框。
但Alpine v3废弃了动态:x-ref绑定的用法,同时对于x-for循环中重复使用的同名静态ref,会自动将所有对应元素按渲染顺序存入数组,你之前的动态绑定写法在v3中不会往$refs里注册任何内容,所以$refs[0]为undefined,调用focus方法就会抛出对应错误。
修改方案
- 给循环内的所有输入框设置统一的静态ref名,不需要动态绑定
- 新增
data-index属性存储当前输入框的索引,用于退格时定位前一个输入框 - 调整x-init和退格事件的逻辑,从ref数组中取对应元素操作
修改后的完整代码如下:
<div x-data="pinHandler()" x-init="$nextTick(() => { $refs.pinInput[0].focus() })" class="flex items-start justify-center min-h-screen w-full bg-white p-16 pt-64"> <div class="relative p-10 pb-8 bg-indigo-500 mx-auto max-w-md rounded-lg shadow-2xl z-50"> <label for="enter-pin" class="block text-3xl mb-2 text-white font-extrabold text-center">Enter PIN</label> <form id="enter-pin" class="flex flex-row flex-wrap justify-center space-x-4" @submit.prevent="handleSubmit()" @paste.prevent="handlePaste($event)"> <template x-for="(input, index) in Array.from({ length: length })" :key="index"> <input @input.prevent="handleInput($event.target)" @keydown.backspace="$event.target.value || focusPreviousRef(+($event.target.dataset.index))" autocomplete="off" :aria-label="`Pin ${index + 1}`" data-lpignore="true" x-ref="pinInput" :data-index="index" class="w-12 mb-4 rounded border border-gray-200 p-3 text-center appearance-none" type="text" maxlength="1"> </template> </form> </div> <p class="absolute bottom-0" x-text="`value: ${value}`"></p> </div>
同时需要同步调整pinHandler中的focusPreviousRef方法逻辑,示例:
function pinHandler() { return { length: 4, // 按实际需求调整PIN码长度 value: '', focusPreviousRef(currentIndex) { if (currentIndex > 0) { this.$refs.pinInput[currentIndex - 1].focus() } }, // 其余handleInput、handlePaste、handleSubmit方法可保持原有逻辑不变 } }
内容的提问来源于stack exchange,提问作者shadi ahmadian
相关产品推荐
相关产品推荐

