繁体   English   中英

在 React 中通过父焦点管理子组件的可见性

[英]Manage child component visibility by parent focus in React

我在 React 中有一个搜索输入组件,它也有很多选项。 我希望在输入焦点集中或框中有交互时出现选项框。 当框的任一搜索输入之外的东西被聚焦时,该框应该消失。 因此,它的行为就像一个非常标准的行为。

有一个问题我不知道如何解决。 选项框内的某些操作会导致框内呈现另一个组件,因此焦点丢失(浏览器聚焦<body> )。 我的组件认为这意味着隐藏选项框。

我找到了一个解决办法——如果容器的blur是由外部的东西引起的,我只会隐藏盒子。 在某些情况下它可以正常工作。 但是,当有一个按钮导致选项框呈现其他内容时,就会出现问题,从而使按钮本身消失。 焦点转到<body>并且我不能再隐藏选项框,除非手动关注搜索输入,然后再关注。

是否有一些技术来管理每个真实或伪焦点的可见性? 在完美的情况下,我想避免以编程方式将我的元素集中在其中,原因有两个:

  1. 我希望autofocus属性能够正常工作。
  2. 选项框的树中确实有很多组件 - 让它们都以编程方式重新聚焦将意味着大量重复代码。

为简单起见,我删除了与问题无关的道具和元素。 但是<OptionsBox />有很多事情要做。

这是我的简化组件:

import { useState } from 'react';
import OptionsBox from './OptionsBox';

export default function Search() {
    const [value, setValue] = useState('');
    const [showOptions, setShowOptions] = useState(false);

    return (
        <div
            tabIndex={-1}
            onFocus={() => setShowOptions(true)}
            onBlur={event => {
                const isChildFocused = event.currentTarget.contains(event.relatedTarget);

                if (!isChildFocused) {
                    setShowOptions(false);
                }
            }}
        >
            <input
                type="text"
                value={value}
                onChange={event => setValue(event.target.value)}
            />
            {showOptions && (
                <OptionsBox />
            )}
        </div>
    );
}

我试图找到一些解决方法来解决这个问题并以这种方式找到它(在链接中)。

  • Autofocus父包装器(取决于要求)。
  • track the click event 如果在里面,则保持焦点,否则模糊<OptionBox />

这是我所做的更改
  • 添加refparentDiv并将其传递给<OptionBox/>进行跟踪
  • 添加2 buttons用于测试onClick focus事件
    • 1st onCLick 用于对焦body
    • 2nd onClick 在<Parent/> / <OptionBox/>内聚焦input
  • 我添加了一个clickHandler来检查您尝试关注的element是否在parentDiv内,如果是,则保持focus ,否则将其blur并将setState设置为false

不确定此解决方案的效率,但您可以尝试(如果尚未尝试过),因为它完全取决于用例。

链接: https://codesandbox.io/s/youthful-hypatia-4mu2x?file=/src/OptionBox.js

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM