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

Wails(Golang原生WebView框架)下双击textarea无法聚焦的问题求助

Wails(Golang原生WebView框架)下双击textarea无法聚焦的问题求助

问题描述

我在使用Wails(Golang原生WebView框架)开发时遇到了一个textarea聚焦的问题:我希望实现双击textarea时取消其只读状态并自动获取焦点,目前的表现是:双击后readonly状态确实成功设为false,textarea也变为可编辑,但textAreaRef.current?.focus()完全不生效,系统环境是Linux Mint。

我的React组件代码如下:

export function EditableText({
  title,
  className,
  outlineOnDoubleClick = false,
  outlineOnClick = true,
}: EditableInputProps) {
  const [inputVal, setInputVal] = useState(title);
  const [isEditing, setIsEditing] = useState(false);
  const [readOnly, setReadOnly] = useState(true);
  const textAreaRef = useRef<null | any>(null);

  const baseClass = `resize-none select-none`;
  const outlineDblClass = `${!isEditing && outlineOnDoubleClick ? "outline-none" : ""}`;
  const outlineSingleClass = `${outlineOnClick ? "" : !outlineOnDoubleClick && "outline-none"}`;
  const finalClass = cn(
    baseClass,
    outlineSingleClass,
    outlineDblClass,
    className,
  );

  return (
    <textarea
      ref={textAreaRef}
      value={inputVal}
      onChange={(e) => setInputVal(e.target.value)}
      className={finalClass}
      readOnly={readOnly}
      onDoubleClick={() => {
        setIsEditing(true);
        setReadOnly(false);
        textAreaRef.current?.focus();
      }}
      onBlur={() => {
        setIsEditing(false);
        setReadOnly(true);
      }}
    />
  );
}

问题根因

React的状态更新是异步批量处理的:当你调用setReadOnly(false)后,React并不会立刻同步更新DOM上的readonly属性。这时候直接调用focus(),DOM中的textarea实际上还处于readonly=true的状态——而只读元素默认是无法获取焦点的,所以聚焦操作自然会失败。

解决方案

这里提供两种可靠的修复方案,都能适配Wails原生WebView的环境:

方案1:用useEffect监听状态变化(推荐)

利用React的useEffect钩子,在readonly状态变为false且DOM完成更新后,再执行聚焦操作:

export function EditableText({
  title,
  className,
  outlineOnDoubleClick = false,
  outlineOnClick = true,
}: EditableInputProps) {
  const [inputVal, setInputVal] = useState(title);
  const [isEditing, setIsEditing] = useState(false);
  const [readOnly, setReadOnly] = useState(true);
  // 建议用具体类型替代any,提升代码健壮性
  const textAreaRef = useRef<null | HTMLTextAreaElement>(null); 

  const baseClass = `resize-none select-none`;
  const outlineDblClass = `${!isEditing && outlineOnDoubleClick ? "outline-none" : ""}`;
  const outlineSingleClass = `${outlineOnClick ? "" : !outlineOnDoubleClick && "outline-none"}`;
  const finalClass = cn(
    baseClass,
    outlineSingleClass,
    outlineDblClass,
    className,
  );

  // 新增:监听readonly状态,变为false时触发聚焦
  useEffect(() => {
    if (!readOnly && textAreaRef.current) {
      textAreaRef.current.focus();
    }
  }, [readOnly]); // 依赖项绑定readonly,状态变化时自动执行

  return (
    <textarea
      ref={textAreaRef}
      value={inputVal}
      onChange={(e) => setInputVal(e.target.value)}
      className={finalClass}
      readOnly={readOnly}
      onDoubleClick={() => {
        setIsEditing(true);
        setReadOnly(false);
        // 移除原有的focus调用,交给useEffect处理
      }}
      onBlur={() => {
        setIsEditing(false);
        setReadOnly(true);
      }}
    />
  );
}

方案2:用requestAnimationFrame延迟执行聚焦

如果不想新增useEffect,可以把聚焦操作放到requestAnimationFrame中,让浏览器完成DOM更新后再执行:

onDoubleClick={() => {
  setIsEditing(true);
  setReadOnly(false);
  // 延迟到下一次浏览器重绘时执行focus,确保DOM已同步状态
  requestAnimationFrame(() => {
    textAreaRef.current?.focus();
  });
}}

方案说明

  • 方案1更符合React的状态管理逻辑:useEffect会在组件状态更新、DOM渲染完成后触发,能精准保证聚焦时机正确,代码可读性也更强。
  • 方案2的requestAnimationFrame会将回调放到浏览器下一次重绘前执行,此时React已经完成了状态到DOM的同步,同样能解决聚焦时机问题。

这两种方案在Linux Mint的Wails WebView环境中都能有效解决你的问题,推荐优先使用方案1。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:10:32