¿Cómo puedo darle el foco de teclado a un DIV y adjuntarle controladores de eventos de teclado?

83

Estoy creando una aplicación en la que quiero poder hacer clic en un rectángulo representado por un DIV y luego usar el teclado para mover ese DIV enumerando los eventos del teclado.

En lugar de usar un detector de eventos para esos eventos de teclado en el nivel de documento, ¿puedo escuchar los eventos de teclado en el nivel DIV, quizás dándole el foco de teclado?

Aquí hay una muestra simplificada para ilustrar el problema:

<html>
<head>
</head>
<body>

<div id="outer" style="background-color:#eeeeee;padding:10px">
outer

   <div id="inner" style="background-color:#bbbbbb;width:50%;margin:10px;padding:10px;">
   want to be able to focus this element and pick up keypresses
   </div>
</div>

<script language="Javascript">

function onClick()
{
    document.getElementById('inner').innerHTML="clicked";
    document.getElementById('inner').focus();

}

//this handler is never called
function onKeypressDiv()
{
    document.getElementById('inner').innerHTML="keypress on div";
}

function onKeypressDoc()
{
    document.getElementById('inner').innerHTML="keypress on doc";
}

//install event handlers
document.getElementById('inner').addEventListener("click", onClick, false);
document.getElementById('inner').addEventListener("keypress", onKeypressDiv, false);
document.addEventListener("keypress", onKeypressDoc, false);

</script>

</body>
</html>

Al hacer clic en el DIV interno, trato de enfocarlo, pero los eventos de teclado posteriores siempre se recogen en el nivel del documento, no en mi oyente de eventos de nivel DIV.

¿Simplemente necesito implementar una noción de enfoque de teclado específica de la aplicación?

Debo agregar que solo necesito esto para funcionar en Firefox.

Paul Dixon
fuente
1
Realmente no es un engaño: preguntó unos dos años antes, y esto es preguntar cómo recibir eventos de teclado en elementos arbitrarios, en lugar de usar la focus()función.
Paul Dixon

Respuestas:

165

Ordenado: agregué el atributo tabindex al DIV de destino, lo que hace que recoja eventos de teclado, por ejemplo

<div id="inner" tabindex="0">
    this div can now have focus and receive keyboard events
</div>

Información obtenida de http://www.w3.org/WAI/GL/WCAG20/WD-WCAG20-TECHS/SCR29.html

Paul Dixon
fuente
6
Además, si no desea que el div obtenga un borde azul punteado cuando está enfocado, puede diseñarlo outline: 0px solid tranparent;. Ver: stackoverflow.com/a/2260788/402807
AlcubierreDrive
4
O establecer tabindex="-1", eso también evitará que obtenga el borde punteado.
troglobit
No puedo hacer que esto funcione en absoluto en Chrome 60 y FF 54. E IE11 mágicamente hace lo correcto incluso sin el tabindex. ¿Esta respuesta está desactualizada?
jlh
Esto no me funciona en el Firefox actual. El navegador maneja la entrada del teclado. Lo mismo ocurre con el violín.
Kwebble
1
deshacerse de la outlineno es accesible. si no le gusta cómo se ve, le recomiendo dar alguna otra indicación visual de que el elemento está enfocado antes de deshacerse deloutline
Sleeparrow
5

La respuesta de Paul funciona bien, pero también puedes usar contentEditable, así ...

document.getElementById('inner').contentEditable=true;
document.getElementById('inner').focus();

Podría ser preferible en algunos casos.

Peter Bagnall
fuente
6
Si hace esto, Chrome 17 coloca un cursor en el elemento en foco y puede escribir cosas en el elemento. No recomendaría esto.
Seppo Erviälä
1
@Seppo, ese es un buen punto. Si está consumiendo los eventos del teclado, entonces no necesariamente podrá editar, pero tener un cursor puede ser complicado dependiendo de lo que esté tratando de hacer. Por cierto, no es solo Chrome 17, sino prácticamente todos los navegadores recientes los que se comportan de esta manera - ciertamente FF y Safari - IE también creo, aunque no lo he probado últimamente
Peter Bagnall