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

如何在单字符长度的OTP(计时器)输入框中覆盖已填充的字符?

如何在单字符长度的OTP(计时器)输入框中覆盖已填充的字符?

我完全懂你遇到的这个麻烦——现在每个单字符输入框填完内容后,得手动按退格键删掉旧字符才能输入新的,用起来特别不顺手。咱们可以通过两个小调整来解决这个问题:

解决思路

  • 自动选中输入框内容:当输入框获得焦点时,自动选中里面已有的字符,这样用户输入新内容时会直接覆盖旧值。
  • 优化输入处理逻辑:确保在输入有效数字时,不管输入框原本有没有内容,都直接替换成新输入的值,同时正常处理焦点跳转。

修改后的代码

咱们来调整你的React组件代码,把这两个优化加进去:

const { useState, useRef } = React;

function App() {
    const [time, setTime] = useState(null);
    const [running, setRunning] = useState(false);
    const [editState, setEditState] = useState(false);
    const [hms, setHms] = useState(Array(6).fill(0));
    const inputs = useRef([]);

    const handleChange = (e, idx) => {
        const {value} = e.target;
        // 只要输入的是单个数字,就直接替换,不管原有内容
        if (value.match(/^\d$/)) {
            const newHms = [...hms];
            newHms[idx] = value;
            setHms(newHms);

            // 输入完成后跳转到下一个输入框,避免越界
            if (idx < 5) {
                inputs.current[idx+1].focus();
            }
        }
    }

    const handleKeyDown = (e, idx) => {
        if (e.key === 'Backspace') {
            const newHms = [...hms];
            // 如果当前输入框有内容,先清空
            if (newHms[idx] !== '') {
                newHms[idx] = '';
                setHms(newHms);
            } else if (idx > 0) {
                // 空的话就跳转到上一个输入框
                inputs.current[idx - 1].focus();
            }
        }
    }

    // 新增:输入框获得焦点时选中内容
    const handleFocus = (e) => {
        e.target.select();
    }

    return (
        <>
            <div id='root' style={{backgroundColor: "#e3b23c", width:"400px", height:"400px"}}>
                {true && <div>
                    {
                        hms.map((_, idx) => {
                            return (
                                <span key={idx}>
                                    <input
                                        type='text'
                                        maxLength="1"
                                        value={hms[idx]}
                                        onKeyDown={(e) => handleKeyDown(e, idx)}
                                        onChange={(e) => handleChange(e, idx)}
                                        onFocus={handleFocus} {/* 绑定焦点事件 */}
                                        ref={(el) => (inputs.current[idx] = el)}
                                        style={{width: '40px',
                                            height: '40px',
                                            margin: '0 5px',
                                            textAlign: 'center',
                                            fontSize: '18px',
                                            border: '1px solid #ccc',
                                            borderRadius: '4px'}
                                        }
                                    />
                                    {(idx == 1 || idx == 3) && <span style={{
                                        fontWeight: 600,
                                        fontSize: "30px"
                                    }}>:</span>}
                                </span>
                            );
                        })
                    }
                </div>}
                <div>
                    Hours : Minutes : Seconds
                </div>
            </div>
        </>
    )
}

ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

关键修改说明

  • 新增了handleFocus函数并绑定到input的onFocus事件,当输入框获得焦点时自动选中内部内容,用户输入新字符就会直接覆盖旧值。
  • 调整了handleChange里的焦点跳转判断:把idx < 6改成idx < 5,因为hms数组是6个元素(索引0到5),避免出现越界访问的问题。
  • 优化了handleChange的逻辑,只要输入的是单个数字,就直接替换原有值,不再受输入框原有内容的限制。

这样修改后,不管输入框有没有填过内容,只要切换到这个输入框,输入新的数字就会直接覆盖旧值,用起来就跟常见的OTP输入框一样顺手啦!

备注:内容来源于stack exchange,提问作者M. Varun Reddy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:34:32