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

输入框内容变更时失焦问题求助(附React+Formik代码)

问题根源分析

你遇到的焦点丢失问题,核心原因是直接通过DOM操作修改input的value(inputRef.current.value = ...),这种方式绕过了React的状态管理机制,会导致React重新评估输入框的DOM状态,进而丢失焦点。另外,组件中虽使用了useRef,但未以受控组件方式管理输入框值,反而用副作用直接篡改DOM,这是触发问题的关键。

解决方案

放弃直接操作DOM的方式,改用受控组件管理输入框状态,结合Formik的字段值处理格式化逻辑,既能保留输入掩码效果,又不会丢失焦点。具体步骤如下:

  • 将输入框改为受控组件:给input添加value属性,绑定格式化后的Formik字段值,让React接管状态管理
  • 优化变更处理逻辑:在handleChange中先处理原始输入,再同步到Formik,格式化逻辑仅在渲染时处理,不直接修改DOM
  • 修复光标位置(可选但重要):格式化后光标可能跳至输入框末尾,添加光标位置修复逻辑,提升用户体验
修正后的代码
export const Component = (props: any) => {
  const inputRef = React.useRef<HTMLInputElement>(null);
  
  // 格式化函数,按需求调整掩码规则
  const formatInputValue = (value: string) => {
    if (!value) return "";
    return value.replace(/^(.{3})(.{0,2})(.{0,2}).*$/, (_, $1, $2, $3) => {
      let result = $1;
      if ($2) result += " " + $2;
      if ($3) result += " " + $3;
      return result;
    });
  };

  const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
    const rawValue = event.target.value.replace(/[^0-9]/g, "");
    // 同步原始纯数字值到Formik的Additional_JKSO字段
    props.formik.setFieldValue("Additional_JKSO", rawValue);
    // 同步格式化后的值到key1字段
    props.formik.setFieldValue("key1", formatInputValue(rawValue));
  };

  // 修复光标位置:避免格式化后光标跳至末尾
  React.useLayoutEffect(() => {
    if (inputRef.current) {
      const input = inputRef.current;
      const cursorPosition = input.selectionStart;
      const originalValue = input.value;
      const formattedValue = formatInputValue(props.formik.values.key1);
      
      if (originalValue !== formattedValue && cursorPosition !== null) {
        let offset = 0;
        for (let i = 0; i < cursorPosition; i++) {
          if (formattedValue[i] === " " && originalValue[i] !== " ") {
            offset++;
          }
        }
        input.setSelectionRange(cursorPosition + offset, cursorPosition + offset);
      }
    }
  }, [props.formik.values.key1]);

  if (props.fieldSchema.fieldKey === "key1") {
    return (
      <div className="flex">
        <div className="text-box">
          <input
            className="text-box__input"
            maxLength={9}
            onChange={handleChange}
            disabled={props.disabled}
            ref={inputRef}
            // 受控组件:绑定格式化后的值
            value={formatInputValue(props.formik.values.key1)}
          />
        </div>
      </div>
    );
  }
  return null;
};
关键说明
  • 受控组件的优势:通过value属性绑定状态,React会自动处理DOM更新,不会出现焦点丢失情况,因为React明确输入框状态是受控的,不会随意重置DOM
  • 避免直接DOM操作:原代码中useLayoutEffect直接修改input的value是反模式,现在改为状态驱动渲染,副作用仅用于修复光标位置,不会触发DOM重置
  • 字段同步:Formik的key1存储格式化后的值,Additional_JKSO存储原始纯数字值,既满足展示需求,又不影响后续数据提交

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 16:45:06