Событие React и blur

у меня есть простая проблема с React и обработкой событий. Мой компонент выглядит так (в основном таблицы):

const MyList = ({ items, onBlur }) =>
<table onBlur={onBlur}}>
    <thead>
    <tr>
        <th>ID</th>
        <th>Title</th>
        <th>Publisher</th>
        <th>Year</th>
        <th>Author</th>
        <th>System</th>
        <th/>
    </tr>
    </thead>
    <tbody>
    {items.map(item => <MyListRow key={item.Id} item={item}/>)}
    </tbody>
</table>;

Я хочу blur событие только если фокус выходит из таблицы. Вместо событие срабатывает на каждом дочернем элементе таблицы, когда он теряет фокус.

В соответствии с docs React позволяет фокусировать события пузырь вверх.

вопрос в том, как я могу получить свой onBlur способ огонь только тогда, когда фокус выходит из-за стола? IOW: как я могу отфильтровать и отбросить нежелательные события, пузырящиеся так, что я показываю только события, которые указывают на потерю фокуса для таблицы?

2 ответов


проблема в том, что таблица на самом деле не имеет концепции фокуса, поскольку это не сам вход.

когда onBlur срабатывает на содержащихся входах, мы проверим relatedTarget на onBlur событие, которое должно быть установлено на элемент, получивший фокус (или null). Затем мы используем функцию, которая будет проходить вверх через parentNodes от этого недавно сфокусированного элемента и убедитесь, что наше событие currentTarget (таблица) не является предком вновь сфокусированного элемента. Если условие проходит предполагается, что таблица больше не имеет фокусировать.

const focusInCurrentTarget = ({ relatedTarget, currentTarget }) => {
  if (relatedTarget === null) return false;
  
  var node = relatedTarget.parentNode;
        
  while (node !== null) {
    if (node === currentTarget) return true;
    node = node.parentNode;
  }

  return false;
}

const onBlur = (e) => {
  if (!focusInCurrentTarget(e)) {
    console.log('table blurred');
  }
}

const MyList = ({ items, onBlur }) => (
  <table onBlur={onBlur}>
    <thead>
      <tr>
        <th>ID</th>
        <th>Title</th>
        <th>Publisher</th>
        <th>Year</th>
        <th>Author</th>
        <th>System</th>
        <th/>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
        <td>
          <input type="text" />
        </td>
      </tr>
    </tbody>
  </table>
);
    
ReactDOM.render(
  <MyList onBlur={onBlur} />,
  document.getElementById('root')
);
table {
  padding: 10px;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
<br />
<input type="text" />

ссылки:

обновление:

удалено использование ReactDOM.findDOMNode


без пользовательские функции и совместимость с Internet Explorer С node.contains и document.activeElement поддерживаются начиная с Internet Explorer 5, это работает:

const onBlur = (e) => { if ( !e.currentTarget.contains( document.activeElement ) ) { console.log('table blurred'); } }

  • Узел.метод contains () возвращает логическое значение, указывающее, является ли узел потомком данного узла или нет.
  • документ.activeElement возвращает текущий элемент, то есть элемент, который получит события нажатия клавиши, если пользователь вводит какие-либо.