如何处理两个特定元素之间的焦点变化

How to handle change of focus between two specific elements

我有两个(或更多)HTML 元素,我想在其中任何一个失去焦点时执行回调,除非焦点在它们之间移动。换句话说,我想从焦点的角度将这些元素视为一个元素并执行 group-onBlur 回调。

使用 React 我试图跟踪每个元素在状态上的焦点,但是当将焦点从元素 a 移动到元素 b 时,onBlura 总是在 b 上的 onFocus 之前发生。此外,由于状态更新可能是异步的,我不确定状态的一致性。

通常情况下,您会在超时后将其关闭并等待几毫秒,然后再触发文本步骤。快速而肮脏的反应代码。

class Test extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
        blurTimer: null
    }
  this.handleBlur = this.handleBlur.bind(this);
  this.handleFocus = this.handleFocus.bind(this);
  }

    clearTimer() {
    if (this.state.blurTimer) {
      window.clearTimeout(this.state.blurTimer);
      this.setState({ blurTimer: null });
    }
  }
  
  processIt() {
    console.log('Process it!!!!');
  }

  handleBlur() {
    this.clearTimer();
    const blurTimer = window.setTimeout(() => this.processIt(), 100);
        this.setState({ blurTimer });
  }

  handleFocus() {
    this.clearTimer();
  }


  render() {
    return (
      <div>
        <h2>foo</h2>
        <input type="text" onBlur={this.handleBlur} onFocus={this.handleFocus} />
        <input type="text" onBlur={this.handleBlur} onFocus={this.handleFocus} />
      </div>
    )
  }
}

ReactDOM.render(<Test />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

您可以存储对每个要“共享”焦点的输入的引用,然后在采取任何操作之前检查是否有任何一个焦点在您的 onBlur 函数中。但是请注意,如果您在模糊发生时立即检查,聚焦元素是 body。要解决此问题,您可以将 onBlur 逻辑包装在延迟 0 毫秒的 setTimeout 调用中。

这是一个例子:

function MyComponent() {
    const aRef = React.useRef(null);
    const bRef = React.useRef(null);

    function onBlurGroup() {
        window.setTimeout(() => {
            if (document.activeElement === aRef.current || document.activeElement === bRef.current) {
                console.log("a or b is focused");
                return;
            }

            console.log("focus lost from group");
            // do blur handling
        }, 0)
    }

    return (
        <div>
            <input ref={aRef} name="a" type="text" onBlur={onBlurGroup}/>
            <input ref={bRef} name="b" type="text" onBlur={onBlurGroup}/>
            <input name="other" type="text"/>
        </div>
    );
}

和一个功能示例(使用基于 class 的组件,因为 Stack 尚不支持挂钩):

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        this.aRef = React.createRef();
        this.bRef = React.createRef();
    }

    onBlurGroup = () => {
        window.setTimeout(() => {
            if (document.activeElement === this.aRef.current || document.activeElement === this.bRef.current) {
                console.log("a or b is focused");
                return;
            }

            console.log("focus lost from group");
            // do stuff
        }, 0)
    }
    
    render() {
        return (
            <div>
                <input ref={this.aRef} name="a" placeholder="A" type="text" onBlur={this.onBlurGroup}/>
                <input ref={this.bRef} name="b" placeholder="B" type="text" onBlur={this.onBlurGroup}/>
                <input name="other" placeholder="Other" type="text"/>
            </div>
        );
    }
}

ReactDOM.render(<MyComponent/>, document.querySelector("#root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>