Jak mogę nasłuchiwać zdarzenia naciśnięcia klawisza na całej stronie?

109

Szukam sposobu na powiązanie funkcji z całą moją stroną (gdy użytkownik naciśnie klawisz, chcę, aby wyzwalał funkcję w moim komponencie.ts)

W AngularJS było łatwo z a, ng-keypressale nie działa (keypress)="handleInput($event)".

Wypróbowałem to z opakowaniem div na całej stronie, ale wygląda na to, że nie działa. działa tylko wtedy, gdy jest na nim skupiony.

<div (keypress)="handleInput($event)" tabindex="1">
L.querter
źródło
Czy próbowałeś window:keypress?
KarolDepka

Odpowiedzi:

203

Użyłbym @HostListener dekorator wewnątrz komponentu:

import { HostListener } from '@angular/core';

@Component({
  ...
})
export class AppComponent {

  @HostListener('document:keypress', ['$event'])
  handleKeyboardEvent(event: KeyboardEvent) { 
    this.key = event.key;
  }
}

Istnieją również inne opcje, takie jak:

obiekt gospodarza w @Componentdekoratorze

Angular zaleca używanie @HostListenerdekoratora zamiast właściwości hosta https://angular.io/guide/styleguide#style-06-03

@Component({
  ...
  host: {
    '(document:keypress)': 'handleKeyboardEvent($event)'
  }
})
export class AppComponent {
  handleKeyboardEvent(event: KeyboardEvent) {
    console.log(event);
  }
}

renderer.listen

import { Component, Renderer2 } from '@angular/core';

@Component({
  ...
})
export class AppComponent {
  globalListenFunc: Function;

  constructor(private renderer: Renderer2) {}

  ngOnInit() {
    this.globalListenFunc = this.renderer.listen('document', 'keypress', e => {
      console.log(e);
    });
  }

  ngOnDestroy() {
    // remove listener
    this.globalListenFunc();
  }
}

Observable.fromEvent

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import { Subscription } from 'rxjs/Subscription';

@Component({
  ...
})
export class AppComponent {
  subscription: Subscription;

  ngOnInit() {
    this.subscription = Observable.fromEvent(document, 'keypress').subscribe(e => {
      console.log(e);
    })
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
yurzui
źródło
2
Werking w porządku. import {HostListener} z „@ angular / core” trzeba dodać. i dzwoń nawet w dowolnym miejscu w komponencie. Nawet zewnętrzny konstruktor również działa dobrze
gnganpath
23
Dzięki za to, ale uwaga dla przyszłych czytelników: jeśli potrzebujesz klawiszy strzałek, użyj klawisza w dół zamiast naciśnięcia klawisza.
Troels Larsen
14
Jeśli potrzebujesz escklucza, użyj keyupzdarzenia. Dziękuję @TroelsLarsen
Aron Lorincz
@yurzui, jak mogę użyć tego zdarzenia dla konkretnego komponentu. nie na całej stronie
kamalav
1
@yurzui Jak mogę wykryć a function-key(F1, F2, F3, ...)?
Arpit Kumar
18

Odpowiedź yurzui nie zadziałała dla mnie, może to być inna wersja RC lub może to być błąd z mojej strony. Tak czy inaczej, oto jak to zrobiłem z moim komponentem w Angular2 RC4 (który jest teraz dość przestarzały).

@Component({
    ...
    host: {
        '(document:keydown)': 'handleKeyboardEvents($event)'
    }
})
export class MyComponent {
    ...
    handleKeyboardEvents(event: KeyboardEvent) {
        this.key = event.which || event.keyCode;
    }
}
Adam
źródło
3
To ta sama, tylko alternatywna składnia i użyłeś keydownzamiastkeypress
Günter Zöchbauer
Jak powiedziałem, prawdopodobnie pomyłka z mojej strony, ale właśnie tego potrzebowałem, żeby to zadziałało. :)
Adam
Jaka byłaby korzyść z tego w porównaniu z użyciem document.addEventListener? Czy to tylko kwestia wyodrębnienia DOM?
Ixonal
@Ixonal # 2 w tych artykułach opisuje lepiej niż ja: angularjs.blogspot.ca/2016/04/ ... Zasadniczo nie jest to metoda „Angular”, ponieważ jest połączona z przeglądarką i nie można jej przetestować. Może nie jest to teraz wielka sprawa, ale to dobry model do naśladowania.
Adam
1
Najnowsze dokumenty zalecają używanie @HostListener: angular.io/docs/ts/latest/guide/ ...
saschwarz
11

Wystarczy dodać do tego w 2019 w Angular 8,

zamiast klawisza musiałem użyć keydown

@HostListener('document:keypress', ['$event'])

do

@HostListener('document:keydown', ['$event'])

Praca w Stacklitz

tshoemake
źródło
Raport Angular 9: zarówno naciśnięcie klawisza, jak i klawisz w dół zarejestrują zwykłe klawisze „asdf”, ale tylko klawisz keydown otrzyma klawisz F4 i inne klawisze funkcyjne. Naciśnięcie klawisza może uzyskać kilka kombinacji klawiszy, takich jak CTRL-Z, keydown interpretuje je oddzielnie (klawisz CTRL, a następnie milisekundy później klawisz Z).
Anders8
4

Jeśli chcesz wykonać dowolne zdarzenie po naciśnięciu dowolnego konkretnego przycisku klawiatury, w takim przypadku możesz użyć @HostListener. W tym celu musisz zaimportować HostListener do pliku ts komponentu.

importuj {HostListener} z '@ angular / core';
następnie użyj poniższej funkcji w dowolnym miejscu w pliku ts komponentu.

@HostListener('document:keyup', ['$event'])
  handleDeleteKeyboardEvent(event: KeyboardEvent) {
    if(event.key === 'Delete')
    {
      // remove something...
    }
  }
Prabhat Maurya
źródło
0

Myślę, że to działa najlepiej

https://angular.io/api/platform-browser/EventManager

na przykład w app.component

constructor(private eventManager: EventManager) {
    const removeGlobalEventListener = this.eventManager.addGlobalEventListener(
      'document',
      'keypress',
      (ev) => {
        console.log('ev', ev);
      }
    );
  }
Whisher
źródło