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

如何让屏幕阅读器聚焦回前一个元素(React场景)

问题解决:Return按钮重新渲染后无法聚焦的问题

问题描述

我需要实现屏幕阅读器友好的交互:点击Return按钮后,该按钮隐藏、Submit按钮显示;点击Submit按钮后,Submit按钮隐藏、Return按钮重新显示并自动获得焦点。尝试用useRef存储Return按钮的引用,但点击Submit后无法让Return按钮聚焦,推测是因为Return按钮被卸载后,存储的是旧的DOM节点引用。

问题原因

当showBucketItem设为false时,BucketItem组件(包含Return按钮)会被完全卸载,对应的DOM节点被销毁。此时保存的ref指向的是已失效的旧DOM节点,而当showBucketItem重新设为true时,React会渲染一个全新的Return按钮DOM节点,旧ref自然无法聚焦到新节点上。

解决方案

方案一:使用useEffect监听组件渲染状态,完成后聚焦

通过useEffect监听showBucketItem的变化,当Return按钮重新渲染完成后,执行聚焦操作:

import BucketItem from "./BucketItem";
import OrderReturn from "./OrderReturn";
import { useRef, useState, useEffect } from "react";

const ParentComp = () => {
  const bucketItemTitle = "Item: ABC";
  const returnButtonTitle = "information for return";
  const returnButtonText = "Return";

  const returnBtnRef = useRef(null);

  const [showBucketItem, setShowBucketItem] = useState(true);
  const [showOrderReturn, setShowOrderReturn] = useState(false);

  const handleClickReturnButton = () => {
    setShowBucketItem(false);
    setShowOrderReturn(true);
  };

  const handleClickSubmitButton = () => {
    setShowBucketItem(true);
    setShowOrderReturn(false);
  };

  // 监听showBucketItem状态,组件重新渲染后聚焦Return按钮
  useEffect(() => {
    if (showBucketItem && returnBtnRef.current) {
      returnBtnRef.current.focus();
    }
  }, [showBucketItem]);

  return (
    <div>
      <h1>Order Details Page</h1>
      {showBucketItem && (
        <BucketItem
          returnBtnRef={returnBtnRef}
          bucketItemTitle={bucketItemTitle}
          returnButtonTitle={returnButtonTitle}
          returnButtonText={returnButtonText}
          handleClickReturnButton={handleClickReturnButton}
        />
      )}
      {showOrderReturn && (
        <OrderReturn handleClickSubmitButton={handleClickSubmitButton} />
      )}
    </div>
  );
};

export default ParentComp;

说明:当showBucketItem变为true时,React完成BucketItem和Return按钮的重新渲染,此时returnBtnRef会指向新的DOM节点。useEffect依赖showBucketItem,确保在组件更新完成后执行聚焦操作,保证DOM节点已存在。

方案二:通过CSS控制显示隐藏,避免组件卸载

如果不想让组件卸载,可以用display属性控制显示隐藏,保持DOM节点始终存在,ref引用不会失效:

  1. 修改ParentComp的返回部分:
return (
  <div>
    <h1>Order Details Page</h1>
    <BucketItem
      returnBtnRef={returnBtnRef}
      bucketItemTitle={bucketItemTitle}
      returnButtonTitle={returnButtonTitle}
      returnButtonText={returnButtonText}
      handleClickReturnButton={handleClickReturnButton}
      style={{ display: showBucketItem ? 'block' : 'none' }}
    />
    <OrderReturn
      handleClickSubmitButton={handleClickSubmitButton}
      style={{ display: showOrderReturn ? 'block' : 'none' }}
    />
  </div>
);
  1. 子组件接收并应用style属性:
    BucketItem组件:
const BucketItem = ({
  bucketItemTitle,
  returnButtonTitle,
  returnButtonText,
  handleClickReturnButton,
  returnBtnRef,
  style
}) => {
  return (
    <div style={style}>
      <div>{bucketItemTitle}</div>
      <ReturnButton
        ref={returnBtnRef}
        returnButtonText={returnButtonText}
        returnButtonTitle={returnButtonTitle}
        handleClickReturnButton={handleClickReturnButton}
      />
    </div>
  );
};

OrderReturn组件:

const OrderReturn = ({ handleClickSubmitButton, style }) => {
  return (
    <div style={style}>
      <label htmlFor="return">Ship Back</label>
      <input type="radio" id="return" />
      <SubmitButton handleClickSubmitButton={handleClickSubmitButton} />
    </div>
  );
};

说明:组件始终存在于DOM中,仅通过CSS控制显示/隐藏,ref引用始终有效,点击Submit后直接调用returnBtnRef.current.focus()即可完成聚焦。

额外修正

注意到原代码中BucketItem传递给ReturnButton的props存在拼写错误:returnButtonTitl应改为returnButtonTitle,修正后才能正确传递标题属性。

内容的提问来源于stack exchange,提问作者A.K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:00:02