javascript - page - title property html
Reaccionar y desenfocar evento (2)
Tengo un problema simple con React y manejo de eventos. Mi componente se parece a esto (básicamente una tabla):
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>;
Quiero que el evento de blur
se dispare solo si el enfoque se sale de la mesa . En su lugar, el evento se activa en cada elemento secundario de la tabla cuando pierde el foco.
De acuerdo con los documentos, React permite que los eventos de enfoque se desarrollen.
La pregunta es: ¿Cómo puedo hacer que mi método onBlur
se onBlur
solo cuando el foco se sale de la mesa? IOW: ¿Cómo puedo filtrar y descartar los eventos no deseados que rebosan para que solo revele los eventos que indican una pérdida de enfoque para la tabla?
El problema es que una tabla no tiene realmente un concepto de enfoque ya que no es una entrada en sí misma.
Cuando onBlur se active en las entradas contenidas, comprobaremos el relatedTarget
del evento onBlur
que se debe establecer en el elemento que tiene el foco RECEPTADO (o null
). Luego usamos una función que se parentNode
hacia arriba a través de parentNode
s desde ese elemento recién enfocado y nos asegurará de que el objetivo parentNode
de nuestro evento (la tabla) no sea un antepasado del elemento enfocado recientemente. Si la condición pasa, se supone que la tabla ya no tiene ningún foco.
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" />
Referencias:
- 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://.com/a/2234986/2957138 (base para nuestra función de verificación de antecesores)
ACTUALIZADO:
Se eliminó el uso de ReactDOM.findDOMNode
Sin funciones personalizadas y compatible con Internet Explorer , dado que node.contains
y document.activeElement
son compatibles desde Internet Explorer 5, esto funciona:
const onBlur = (e) => { if ( !e.currentTarget.contains( document.activeElement ) ) { console.log(''table blurred''); } }
- El método Node.contains () devuelve un valor booleano que indica si un nodo es descendiente de un nodo determinado o no.
- Document.activeElement devuelve el elemento enfocado actualmente, es decir, el elemento que obtendrá eventos de pulsación de tecla si el usuario escribe alguno.