第一次和第二次点击之间的RxJS mouseenter

时间:2017-02-25 00:05:43

标签: javascript rxjs

我正在尝试在列表中任何项目的第一次和第二次点击之间捕获项目列表上的悬停事件。

E.g。

  • 用户点击列表中的项目
  • 悬停流项目会发出事件
  • 用户在列表中执行第二次点击,并且悬停事件停止

我已按如下方式设置了一个可观察的流:

let items = document.getElementsByClassName("item");
let itemClicks = Rx.Observable.fromEvent(items, "click");
let itemHover = Rx.Observable.fromEvent(items, "mouseenter");

let clicksWithFlag = itemClicks.scan((acc, val) => ({ val: val.target.innerHTML, firstClick: !acc.firstClick}), {});

//create stream of 1st clicks
let firstClicks = clicksWithFlag.filter(x => x.firstClick).pluck('val');
//create stream of second clicks
let secondClicks = clicksWithFlag.filter(x => !x.firstClick).pluck('val');

let hoverBetweenFirstAndSecondClick = firstClicks.flatMap(x => itemHover.takeUntil(secondClicks));

我遇到的问题是itemHover.takeUntil(secondClicks)没有结束itemHover流。我认为这与源自同一个观察者的firstClicks和secondClicks有关,但无法弄明白。

如果我将takeUntil(secondClicks)换成任何其他流(例如停止按钮),它就可以工作。

请参阅此JSBin以获取示例:https://jsbin.com/dotapis/edit?js,console,output

希望有人可以提供帮助。我正在尝试使用RxJS构建范围选择器,但我开始认为将流拆分为第一次和第二次单击可能不是最佳路径。

更新

刚刚尝试使用BaconJS,我可以使用几乎完全相同的代码。 https://jsbin.com/fobumu/edit?js,console,output

我确信问题在于非惯用的流,但不确定原因。

1 个答案:

答案 0 :(得分:0)

看起来你可能正试图强制使用命令式方法进入函数式编程库,这就是为什么它变得如此复杂以至于使其工作。 这可能更简单:

let items = document.getElementsByClassName("item");
let button = document.getElementById("button1");

let itemClicks = Rx.Observable.fromEvent(items, 'click');
let itemHover = Rx.Observable.fromEvent(items, 'mouseenter');

let buttonClicks = Rx.Observable.fromEvent(button, 'click');

let clicksWithFlag = itemClicks.scan((acc, val) => (
  { val: val.target.innerHTML, firstClick: !acc.firstClick}
), {});

clicksWithFlag
  .combineLatest(itemHover, (click, hover) => ({click, hover}))
  .filter(arg => arg.click.firstClick)
  .map(arg => arg.hover.target.innerHTML)
  .subscribe(hover => console.warn('btn: hover: ' + hover));

作为使用Rx时的一般建议,请尝试查找声明性解决方案。如果您开始考虑如何转换流以获得所需内容而不是执行此操作的步骤,那么事情就会变得更容易。

希望它有所帮助,祝你好运!