#rxjs #rxjs-pipeable-operators
#rxjs #rxjs-pipeable-operators
Вопрос:
Я пытаюсь создать свои собственные события щелчка, удержания и перетаскивания, используя Rxjs и события mousedown, mouseup и mousemove. В моих попытках используется несколько потоков, которые начинаются с события наведения курсора мыши, каждый с takeUntil, который прослушивает выбросы из других потоков. В принципе, как только один из потоков «заявил» действие (т. Е. передал все требования и выдал значение), другие наблюдаемые объекты должны завершиться без выбросов.
Я просмотрел другие ответы и подумал, что это может иметь какое-то отношение к асинхронному запуску таймера, но это происходит между потоками, которые не полагаются на таймер, например, перетаскивание и щелчок. Я играл в codesandbox.io использование rxjs версии 6.
takeUntil также должны располагаться на внутренних наблюдаемых, поскольку я не хочу, чтобы внешние наблюдаемые запускались один раз и завершались.
Код показан ниже:
const mouse_Down$ = fromEvent(document, "mousedown").pipe(
tap(event => event.preventDefault())
);
const mouse_Up$ = fromEvent(document, "mouseup").pipe(
tap(event => event.preventDefault())
);
const mouse_Move$ = fromEvent(document, "mousemove");
const mouse_drag$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
mouse_Move$.pipe(takeUntil(merge(mouse_Up$, mouse_Hold$, mouse_drag$)))
)
).subscribe(event => console.log("Drag"));
const mouse_Hold$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
timer(1000).pipe(takeUntil(merge(mouse_drag$, mouse_Click$)))
)
).subscribe(event => console.log("Hold"));
const mouse_Click$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
mouse_Up$.pipe(takeUntil(mouse_drag$, mouse_Hold$))
)
).subscribe(event => console.log("Click"));
Ожидаемое поведение:
Если пользователь перемещает мышь в течение 1 секунды после события mousedown, mouse_drag$
поток должен начать излучать, и mouse_Click$/mouse_Hold$
внутренние наблюдаемые объекты должны завершиться (благодаря takeUntil(mouse_drag$)
без излучения и ожидания следующего mouse_down$
излучения.
Если кнопка мыши остается нажатой более 1 секунды без перемещения, mouse_Hold$
должна произойти эмиссия, а mouse_drag$/mouse_click$
внутренняя наблюдаемая должна завершиться (благодаря takeUntil(mouse_Hold$)
без эмиссии и ожидания следующей mouse_down$
эмиссии.
Фактическое поведение: В данный момент mouse_Drag$
будет выделяться, mouse_Hold$
будет выделяться через одну секунду и mouse_Click$
будет выделяться при отпускании кнопки.
Мой вопрос в том, почему испускающий mouse_Drag$
поток не приводит к завершению внутренней observable mouse_Hold$
и mouse_Click$
без испускания?
Ответ №1:
Take until должно быть в конце вашей цепочки
Это отменит всю цепочку.
const { fromEvent } = rxjs;
const { tap, takeUntil, mergeMap, merge } = rxjs.operators;
const mouse_Down$ = fromEvent(document, "mousedown").pipe(
tap(event => event.preventDefault())
);
const mouse_Up$ = fromEvent(document, "mouseup").pipe(
tap(event => event.preventDefault())
);
const mouse_Move$ = fromEvent(document, "mousemove");
const mouse_drag$ = mouse_Down$
.pipe(
mergeMap(mouseDownEvent =>
mouse_Move$
),
takeUntil(mouse_Up$)
).subscribe(event => console.log("Drag"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
Комментарии:
1. Спасибо за ответ, Адриан. Проблема с переносом takeUntil во внешнюю наблюдаемую заключается в том, что она завершит это наблюдаемое, и никакие будущие события mouse_drag $ не генерируются. т. Е. вы можете перетащить только один раз, и тогда никакие другие перетаскивания не будут зарегистрированы.
2. На самом деле, если вы хотите завершить mouse_Hold $ и mouse_Click $ — тогда они перестанут выделять — это ожидается. Или вы хотите их воссоздать? Из сделать один выброс результата наблюдаемым, если мышь перетаскивается более 1 секунды. А затем повторить эту логику?
Ответ №2:
Для уточнения:
- которые вы хотите выбросить из mouse_Hold $, если мышь удерживается более 1 секунды.
- Вы хотите получить значения из mouse_drag $, если менее чем через 1 секунду после выпадающего списка мыши и перемещения мыши.
Вам не нужно ничего завершать, поскольку в противном случае все поведение сработает только один раз. Итак, планируйте: 3. mouse_drag $ — Если mousedown — установите флажок mouseMove на 1 секунду. Если mouseMove выдает — переключитесь на значения mouseMove 4. mouse_Hold$ — если mouseDown — проверьте mouseMove на 1 секунду. Если mouseMove не выдает — переключитесь на mouseHold и заставьте его выдавать ‘Hold’
let Rx = window['rxjs'];
const {defer, of, timer, fromEvent, merge, race} = Rx;
const {switchMap, repeat, tap, takeUntil, filter} = Rx.operators;
const {ajax} = Rx.ajax;
console.clear();
const mouse_Down$ = fromEvent(document, "mousedown");
const mouse_Up$ = fromEvent(document, "mouseup");
const mouse_Move$ = fromEvent(document, "mousemove");
const timer$ = timer(2000);
mouse_Hold$ = mouse_Down$.pipe(
switchMap((downEvent) => {
return timer$.pipe(
switchMap((time) => of('HOLD'))
);
}),
takeUntil(merge(mouse_Up$, mouse_Move$)),
repeat(mouse_Down$)
)
mouse_Hold$.subscribe(console.warn);
mouse_drags$ = mouse_Down$.pipe(
switchMap(() => mouse_Move$),
takeUntil(mouse_Up$, $mouse_Hold),
repeat(mouse_Down$)
)
mouse_drags$.subscribe(console.log);
Вот codepen:https://codepen.io/kievsash/pen/oOmMwp?editors=0010