Как обрабатывать изменение фокуса между двумя конкретными элементами

#javascript #html #reactjs #focus #blur

#javascript #HTML #reactjs #фокус #размытие

Вопрос:

У меня есть два (или более) Элементы HTML и я хочу выполнять обратный вызов всякий раз, когда какой-либо из них теряет фокус, за исключением случаев, когда фокус перемещается между ними. Другими словами, я хочу рассматривать эти элементы как один с точки зрения фокуса и выполнять групповой onBlur обратный вызов.

Используя React, я пытался отслеживать фокус каждого элемента на состоянии, но при перемещении фокуса с элемента a на элемент b onBlur on a всегда происходит перед onFocus on b . Кроме того, поскольку обновление состояния может быть асинхронным, я не уверен в согласованности состояния.

Комментарии:

1. Можете ли вы поделиться примером кода?

Ответ №1:

Вы можете сохранить ссылки на каждый из входных данных, которые вы хотите «поделиться» фокусом, а затем проверить, сфокусирован ли какой-либо из них в вашей onBlur функции, прежде чем предпринимать какие-либо действия. Однако обратите внимание, что сфокусированный элемент — это body if, который вы проверяете сразу, когда происходит размытие. Чтобы обойти это, вы можете обернуть свою onBlur логику в setTimeout вызов с задержкой 0 в мс.

Вот пример:

 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>
    );
}
 

И функционирующий образец (с использованием компонента на основе классов, поскольку 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"/> 

Ответ №2:

Обычно вы выполняете это с таймаутом и ждете несколько миллисекунд, прежде чем запускать текстовый шаг. Быстрый и грязный код react.

 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>