首页 > 解决方案 > Focus Trap React 和 2 个弹出窗口中的一些组件

问题描述

我有 2 个弹出窗口(我在2个弹出窗口中重用 了 CloseButton(组件)和Modal(组件))并且根本需要做焦点陷阱。我会回答 4 个更好的方法。

  1. 1个弹出屏幕,组件:ModalLogin- Modal - CloseButton

我读到了一些钩子:useRef()forwardRef(props, ref) 但我不明白为什么它在我的情况下不起作用。我正在努力寻找解决方案。我需要帮助 :)

在 ModalLogin 中,我尝试做一个焦点陷阱。为此,我标记了当移动到 1 和最后一个元素时焦点应该发生的事情。我需要传递通过 Modal-CloseButton 获得的 ref 挂钩。我读到您不能只将 refs 转移到功能组件。我尝试在传输它的必要组件中使用 forwardref 钩子,这就是我所做的:

所有没有焦点陷阱和钩子的链接!。

https://github.com/j3n4r3v/ligabank-credit/blob/master/src/components/form-login/modal-login.jsx [模态登录完整]

    const ModalLogin = () => {
        const topTabTrap* = useRef();
        const bottomTabTrap* = useRef();
        const firstFocusableElement = useRef();
        const lastFocusableElement = useRef();
    
    useEffect(() => {
         const trapFocus = (event) => {
            if (event.target === topTabTrap.current) {
                lastFocusableElement.current.focus()
            }
            if (event.target === bottomTabTrap.current) {
                firstFocusableElement.current.focus()
            }
        }
        document.addEventListener('focusin', trapFocus)
        return () => document.removeEventListener('focusin', trapFocus)
      }, [firstFocusableElement, lastFocusableElement])
    
      return ( 
            <Modal onCloseModal={() => onCloseForm()} ref={lastFocusableElement}>
    
            <form >
                <span ref={topTabTrap} tabIndex="0" />
                    <Logo />
                    <Input id="email" ref={firstFocusableElement} />
                    <Input id="password" />
                    <Button type="submit" />
                <span ref={bottomTabTrap} tabIndex="0"/>
            </form>
    
        </Modal>
    );
    };

https://github.com/j3n4r3v/ligabank-credit/blob/master/src/components/modal/modal.jsx [模态完整]

const Modal = forwardRef(({ props, ref }) => {
      const { children, onCloseModal, ...props } = props;
      const overlayRef = useRef();
      useEffect(() => {
        const preventWheelScroll = (evt) => evt.preventDefault();
            document.addEventListener('keydown', onEscClick);
            window.addEventListener('wheel', preventWheelScroll, { passive: false });
        return () => {
            document.removeEventListener('keydown', onEscClick);
            window.removeEventListener('wheel', preventWheelScroll);
        };
    });
    const onCloseModalButtonClick = () => {
        onCloseModal();
    };

    return (
        <div className="overlay" ref={overlayRef}
            onClick={(evt) => onOverlayClick(evt)}>
            <div className="modal">
                <CloseButton
                    ref={ref}
                    onClick={() => onCloseModalButtonClick()}
                    {...props}
                />
                    {children}
            </div>
        </div>
    );
    });

https://github.com/j3n4r3v/ligabank-credit/blob/master/src/components/close-button/close-button.jsx [CloseButton full]

const CloseButton = forwardRef(({ props, ref }) => {
        const {className, onClick, ...props} = props;
     return (
        <button className={`${className} close-button`}
            onClick={(evt) => onClick(evt)}
            tabIndex="0"
            ref={ref}
                {...props}
            >Close</button>
    );
    });

现在我有很多错误,例如:1 - 无法读取未定义的属性(读取“孩子”) - 模态,2 - ... className undefined in CloseButton 等。

  1. 2个弹出屏幕,组件:模态(在1个弹出窗口中重用)-InfoSuccess- CloseButton(在1个弹出窗口中重用)

我只有 1 个交互式元素 - 按钮(tabindex),仅此而已。现在我对带有焦点陷阱的 2 个弹出窗口一无所知((

https://github.com/j3n4r3v/ligabank-credit/blob/master/src/components/success-modal/success-modal.jsx [SuccessModal 完整]

    const SuccessModal = ({ className, onChangeVisibleSuccess }) => {
    return (
        <Modal onCloseModal={() => onChangeVisibleSuccess(false)}>
            <InfoSuccess className={className} />
         </Modal>
    );
};

https://github.com/j3n4r3v/ligabank-credit/blob/master/src/components/info-block/info-block.jsx [信息块完整]

    const InfoBlock = ({ className, title, desc, type }) => {
    return (
        <section className={`info-block ${className} info-block--${type}`}>
            <h3 className="info-block__title">{title}</h3>
            <p className="info-block__desc">{desc}</p>
        </section>
    );
};

     const InfoSuccess = ({ className }) => (
       <InfoBlock
         title="Спасибо за обращение в наш банк."
         desc="Наш менеджер скоро свяжется с вами по указанному номеру телефона."
         type="center"
         className={className}
    />
);

我知道 3 in 1 = 1 组件,并且在使用 Focus-Trap 的弹出窗口中没有问题。但我想了解我的案例,它是否真实存在以及最佳实践。

标签: reactjsreact-hooksmodal-dialogfocus

解决方案


推荐阅读