typescript - Αναδημιουργία του event contextmenu σε RxJS
Θέλω να αναδημιουργήσω το γεγονός contextmenu από τα γεγονότα αφής στο RxJS επειδή το iOS δεν υποστηρίζει το γεγονός contextmenu στην αφή.
Με απλή γλώσσα, αυτό το παρατηρήσιμο θα πρέπει να εκπέμπει όταν:
- το γεγονός touchstart συνέβη
- για 2000ms (ουσιαστικά παρατεταμένο πάτημα)
- ακολουθείται από touchend
Δεν θα πρέπει να εκπέμπει όταν:
- Το touchend συμβαίνει σε λιγότερο από 2000ms
- το συμβάν touchstart ακολουθείται από το συμβάν touchmove
Δεν μπορώ να καταλάβω πώς να παραλείψω αν το touchend συμβεί νωρίτερα ή αν το touchstart ακολουθείται από touchmove. Αυτό είναι ό,τι έχω μέχρι στιγμής:
const touchStart$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchstart");
const touchEnd$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchend");
const touchMove$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchmove");
const contextmenu$ = touchStart$.pipe(
switchMap(event => touchEnd$.pipe(mapTo(event))),
switchMap(event => timer(2000).pipe(mapTo(event), takeUntil(merge(touchEnd$, touchMove$))))
);
contextmenu$.subscribe($event => {
console.log("CONTEXTMENU EVENT HAPPENED");
});
Απάντηση #1
Η λύση σας μπορεί να απλοποιηθεί λίγο. Το εσωτερικό mapTo δεν είναι απαραίτητο, αν δεν ξαναχρησιμοποιείτε το όνομα event, μπορείτε απλώς να χρησιμοποιήσετε ένα μόνο mapTo στο τέλος του pipe σας. Επίσης, μπορεί να θέλετε να χρησιμοποιήσετε take(1) αντί για takeUntil(touchMove$) στο εσωτερικό switchMap αφού θέλετε να τερματίσετε το stream μετά την πρώτη εκπομπή:
const longPress$ = this.touchStart$.pipe(
switchMap(event => timer(2000).pipe(
takeUntil(merge(touchMove$, touchEnd$)),
switchMap(() => touchEnd$.pipe(take(1))),
mapTo(event)
))
);
Υποθέτω ότι πήρες τη συμπεριφορά που ήθελες, αλλά νομίζω ότι κανονικά ένα παρατεταμένο πάτημα θα ενεργοποιηθεί όταν περάσει η διάρκεια· δηλαδή, δεν χρειάζεται να περιμένουμε για το γεγονός touchend. Αν συνέβαινε αυτό, γίνεται ακόμα πιο απλό:
const longPress$ = this.touchStart$.pipe(
switchMap(event => timer(2000).pipe(
takeUntil(merge(touchMove$, touchEnd$)),
mapTo(event)
))
);
Ορίστε μερικά StackBlitzes με πολύχρωμη καταγραφή: Αρχικό | Απλοποιημένο
Απάντηση #2
Σκέφτηκα μια πιθανή λύση:
const touchStart$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchstart");
const touchEnd$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchend");
const touchMove$ = fromEvent<TouchEvent>(this.el.nativeElement, "touchmove");
const contextmenu$ = touchStart$.pipe(
switchMap(event =>
timer(2000).pipe(
mapTo(event),
takeUntil(merge(touchMove$, touchEnd$)),
switchMap(event => touchEnd$.pipe(mapTo(event), takeUntil(touchMove$)))
)
)
);
contextmenu$.subscribe($event => {
console.log("CONTEXT MENU EVENT HAPPENED");
});
