Jak mogę nadać fokus klawiatury do DIV i dołączyć do niego programy obsługi zdarzeń klawiatury?

84

Buduję aplikację, w której chcę mieć możliwość kliknięcia prostokąta reprezentowanego przez DIV, a następnie użyj klawiatury, aby przenieść ten DIV, wyświetlając zdarzenia klawiatury.

Zamiast używać detektora zdarzeń dla tych zdarzeń klawiatury na poziomie dokumentu, czy mogę nasłuchiwać zdarzeń klawiatury na poziomie DIV, być może poprzez ustawienie fokusu na klawiaturze?

Oto uproszczony przykład ilustrujący problem:

<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>

Po kliknięciu wewnętrznego DIV staram się nadać mu fokus, ale kolejne zdarzenia klawiatury są zawsze odbierane na poziomie dokumentu, a nie na moim odbiorniku zdarzeń na poziomie DIV.

Czy muszę po prostu zaimplementować specyficzne dla aplikacji pojęcie fokusu na klawiaturze?

Powinienem dodać, że potrzebuję tego tylko do pracy w Firefoksie.

Paul Dixon
źródło
1
Niezupełnie oszustwo - zapytał jakieś dwa lata wcześniej, a to pytanie, jak odbierać zdarzenia klawiatury na dowolnych elementach, zamiast używać focus()funkcji.
Paul Dixon,

Odpowiedzi:

166

Sorted - dodałem atrybut tabindex do docelowego DIV, co powoduje, że np. Odbiera zdarzenia z klawiatury

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

Informacje zebrane z http://www.w3.org/WAI/GL/WCAG20/WD-WCAG20-TECHS/SCR29.html

Paul Dixon
źródło
7
Ponadto, jeśli nie chcesz, aby element DIV miał przerywaną niebieską ramkę, gdy jest skupiony, możesz go nadać stylowi outline: 0px solid tranparent;. Zobacz: stackoverflow.com/a/2260788/402807
AlcubierreDrive
4
Lub ustaw tabindex="-1", to również zapobiegnie uzyskaniu przerywanej ramki.
troglobit
Nie mogę tego w ogóle uruchomić w Chrome 60 i FF 54. A IE11 magicznie robi to, co trzeba, nawet bez tabindex. Czy ta odpowiedź jest nieaktualna?
jlh
To nie działa dla mnie w obecnej przeglądarce Firefox. Przeglądarka obsługuje wprowadzanie z klawiatury. To samo dotyczy skrzypiec.
Kwebble
1
pozbycie się outlinenie jest dostępne. jeśli nie podoba ci się wygląd, polecam dać inne wizualne wskazanie, że element jest skupiony, zanim pozbędziesz sięoutline
sleeparrow
5

Odpowiedź Paula działa dobrze, ale możesz również użyć contentEditable, w ten sposób ...

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

W niektórych przypadkach może być lepsze.

Peter Bagnall
źródło
6
Jeśli to zrobisz, Chrome 17 umieszcza kursor na elemencie na fokusie i możesz wpisywać rzeczy na elemencie. Nie polecałbym tego.
Seppo Erviälä
1
@Seppo, to dobra uwaga. Jeśli konsumujesz zdarzenia klawiatury, niekoniecznie będziesz w stanie edytować, ale posiadanie kursora może być bałagan w zależności od tego, co próbujesz zrobić. Nawiasem mówiąc, to nie tylko Chrome 17, ale prawie wszystkie najnowsze przeglądarki zachowują się w ten sposób - na pewno FF i Safari - IE też uważam, chociaż ostatnio tego nie testowałem
Peter Bagnall