Событие 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
). Затем мы используем функцию, которая будет проходить вверх через parentNode
s от этого недавно сфокусированного элемента и убедитесь, что наше событие 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" />
ссылки:
- http://www.w3schools.com/jsref/event_onblur.asp
- http://www.w3schools.com/jsref/event_currenttarget.asp
- http://www.w3schools.com/jsref/event_focus_relatedtarget.asp
- https://stackoverflow.com/a/2234986/2957138 (основа для проверки нашего предка функция)
обновление:
удалено использование 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 возвращает текущий элемент, то есть элемент, который получит события нажатия клавиши, если пользователь вводит какие-либо.