duuliy

mac和window中文输入法下,在输入框中输入英文的防抖处理的兼容

2024-12-8

背景

遇到个很奇怪的问题:window 中文输入法下,在输入框(onChange做了防抖)中输入英文,会导致:每次按键后的总字符串会累加按键前的输入值。。。

先看以下demo,仅针对受控组件(非受控无本文讨论问题),代码跑起来后在中文输入法下的输入框中输入英文 d和o。

https://codesandbox.io/p/sandbox/ji-ben-shi-yong-antd-4-24-16-forked-56y8m3

import React, { useState, useCallback } from "react";
import "antd/dist/antd.css";
import "./index.css";
import { Input } from "antd";
import { useDebounce } from "ahooks";
import { debounce } from "lodash";

const App: React.FC = () => {
  const [keyword, setKeyword] = useState("");
  const [keyword2, setKeyword2] = useState("");
  const debouncedKeyword = useDebounce(keyword, { wait: 300 });

  const onSearch = (e) => {
    const value = e.target.value;
    console.log(555, value);
    setKeyword(value);
  };

  console.log(666, keyword);
  console.log(777, debouncedKeyword);

  // 输入很快可能掉中间的字母
  const onSearch22 = useCallback(
    debounce((value) => {
      console.log(111, value);
      setKeyword2(value);
    }, 1000),
    []
  );

  const onSearch2 = (e) => {
    console.log(7777, e.target.value);
    onSearch22(e.target.value);
  };

  return (
    <>
      &#123;/* 受控组件 */&#125;
      <Input value=&#123;keyword&#125; onChange=&#123;onSearch&#125; />;
      &#123;/*  输入很快可能 字母延迟显示 用户体验不好 */&#125;
      <Input value=&#123;debouncedKeyword&#125; onChange=&#123;onSearch&#125; />;
      <Input value=&#123;keyword2&#125; onChange=&#123;(e) => onSearch2(e)&#125; />;
    </>
  );
&#125;;

export default App;

在mac电脑的chrome下,三个输入框中输入,打印结果如下

图片
很明显没有任何问题

在window电脑的chrome下,三个输入框中输入,打印结果如下

图片
图片
图片

可以看到第一张没问题。
第二张图,输入d后没有问题,当时输入o后,555和666先打印空串然后再打印 ‘ddo’。
第三张图,输入d后没有问题,当时输入o后,7777先打印空串然后再打印 ‘ddo’。

此时猜想是否与ahooks或lodash的防抖或内部定时器在window的兼容有关,于是手写防抖如下


import React, &#123; useState, useCallback &#125; from "react";
import "antd/dist/antd.css";
import "./index.css";
import &#123; Input &#125; from "antd";

function debounce(fn, wait = 50) &#123;
  let timer;
  return function () &#123;
    if (!timer) &#123;
      fn.apply(this, arguments);
    &#125;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => &#123;
      fn.apply(this, arguments);
    &#125;, wait);
  &#125;;
&#125;

const App: React.FC = () => &#123;
  const [keyword2, setKeyword2] = useState("");

  const onSearch22 = useCallback(
    debounce((value) => &#123;
      console.log(111, value);
      setKeyword2(value);
    &#125;, 1000),
    []
  );

  const onSearch2 = (e) => &#123;
    console.log(7777, e.target.value);
    onSearch22(e.target.value);
  &#125;;

  return (
    <>
      <Input value=&#123;keyword2&#125; onChange=&#123;(e) => onSearch2(e)&#125; />;
    </>
  );
&#125;;

export default App;

结果和图三打印一致,猜测window和mac 在中文输入法(要弹小窗那种)在定时器加持下处理闭包的方式不同。。。于是chatGPT查询验证,果然如此!

解决办法

window中有本文问题,mac中使用:
1.尝试input方法3,如果定时时间稍长,快速输入字母,只会有最后一个字母生效。即使合理的定时时间都有可能会影响用户体验。
2.尝试input方法2,如果定时时间稍长,输入很快 字母会延迟显示,同样用户体验不好。

window中无本文问题,mac中使用:
3.尝试input方法1,展示不用防抖,防抖出来的keyword作为聚合数据排序等使用。(推荐)

有办法解决input方法3和input方法2在window中问题吗?

https://blog.csdn.net/Heartbroken_man/article/details/131199571

查询得compositionStart和compositionEnd来处理,听说vue的v-model也是这样处理.
实测:对受控Input组件无效