Reactjs RxJS DOM暂停可观察,而另一个;是否正在拖动;?

Reactjs RxJS DOM暂停可观察,而另一个;是否正在拖动;?,reactjs,rxjs,rxjs-dom,Reactjs,Rxjs,Rxjs Dom,更新 我尝试在这里制作一个独立版本: 它和我的本地版本不太一样,但我希望它足够相似,你能看到我想要去的地方 我没有得到完全相同的行为,因为我将侦听器目标更改为document,这似乎对一些人有所帮助 另外,我正在使用RXJSV5和React的最新版本 仍然掌握着 我有两个可观察对象:一个订阅表上的mouseover x坐标以显示调整大小的列,另一个允许用户在该列上拖动 粗略地说,第一种方法看起来是这样的(在React组件中的componentDidUpdatelifecycle方法中定义了以下

更新

我尝试在这里制作一个独立版本:

它和我的本地版本不太一样,但我希望它足够相似,你能看到我想要去的地方

我没有得到完全相同的行为,因为我将侦听器目标更改为
document
,这似乎对一些人有所帮助

另外,我正在使用RXJSV5和React的最新版本


仍然掌握着

我有两个可观察对象:一个订阅表上的mouseover x坐标以显示调整大小的列,另一个允许用户在该列上拖动

粗略地说,第一种方法看起来是这样的(在React组件中的
componentDidUpdate
lifecycle方法中定义了以下所有方法):

这很有效,给了我这个:

所以现在我想提供实际的“拖动”行为,我试着建立一个新的可观察对象,就像这样

// `resizerEl` is the black element that appears on hover
// from the previous observable; it's just a div that gets
// repositioned and conditionally created
Rx.DOM.mousedown(resizerEl)
  .flatMap(md => {
    md.preventDefault()

    return Rx.DOM.mousemove(tableEl)
      .map(mm => mm.x - md.x)
      .takeUntil(Rx.DOM.mouseup(document))
  })
  .subscribe(/* do column resizing stuff */)
这有三个问题:

  • 一旦我完成了第一次“拖”,我就不能再拖了。我的理解是,
    一直持续到
    完成可观察对象,我不确定如何“重新启动”它
  • 当我拖动时,来自第一个可观察对象的
    mousemove
    仍处于活动状态,因此当我的
    x
    位置发生足够的变化以触发该行为时,我的黑色div将消失
  • 第二个可观察对象上的绑定似乎并不总是触发(这是不可靠的)。我认为这里可能会出现竞争条件或其他情况,因为有时我会刷新页面,并获得一次阻力(从#1),而其他时候我根本无法获得阻力
  • 注意:首先,在一次干净的刷新之后,我不能拖动控制柄(#3),然后我刷新,并且我不能从第一个可观察对象拖动控制柄越过边界设置——当鼠标的x坐标进入和离开该封套(#2)时,黑色大小调整器条消失并重新出现


    我已经在这个问题上讨论了很长一段时间了,如果你能了解我到底做错了什么,我将不胜感激。简言之,我想要

    • 当我拖动时,第一个观察到“暂停”,然后在完成拖动后恢复
    • 拖动完成后,第二个可观察到的未“完成”(或“重新启动”)
    • 第二个可观察到可靠工作
    如前所述,我目前在React组件的
    componentDidUpdate
    生命周期方法中设置了此逻辑,其形状大致如下:

    componentWillUpdate() {
      // bail if we don't have the ref to our table
      if (!tableEl) {
        return;
      }
    
      // try not to have a new Observable defined on each component update
      if (!this.resizerDrag$ && this.resizer) {
        this.resizerDrag$ = // second Observable from above
      }
    
      // try not to have a new Observable defined on each component update
      if (!this.resizerPos$) {
        this.resizerPos$ = // first Observable from above
      }
    }
    

    我现在已经对此进行了一些讨论,我不认为这个答案是完整的,但我想与大家分享我的见解。希望一个更先进的RxJS思维会出现,我们可以一起努力解决:)

    我在CodePen中重新创建了一个“lite-er”版本,使用了一些轻jQuery操作,而不是React。以下是我目前掌握的情况:

    第一个可观察到的在拖动时“暂停”,然后在完成拖动后恢复 解决第一个问题有助于解决其他两个问题。基于我为获得我的
    resizerEl
    所做的工作,我感觉它是在组件的
    render
    方法中基于
    this.state
    中的内容进行渲染的。如果这是真的,这意味着当第一个可观察对象仍然有能力创建和销毁
    resizerEl
    ,即使第二个可观察对象正在监听。这意味着,
    resizerEl
    将不再能够生成任何事件,即使在鼠标移动之前,可观察对象不会完成

    在我的例子中,我注意到如果你移动鼠标的速度足够快,超出了你试图拖动的宽度,它将消除
    resizerEl
    ,这是我们想要的,但不是在我们试图拖动某个东西的时候

    我的解决方案:我在“组件”的“状态”中引入了另一个变量。当我们在
    resizerEl
    上鼠标时,这将设置为
    true
    ,然后当我们再次向上鼠标时,这将设置为
    false

    然后我们使用
    switchMap

      Rx.DOM.mousemove(tableEl)
      .switchMap(function(event) {
        return this.state.mouseIsDown ? Rx.Observable.never() : Rx.Observable.of(event);
      })
      .map(...
    
    也许有更好的方法来做,而不是仅仅把
    事件
    放回一个可观察的位置,但这是我工作的最后一部分,我的大脑有点崩溃了。这里的关键是切换到
    可观察。当鼠标按下时,千万不要
    ,这样我们就不会在操作员链上走得更远

    实际上,一件好事是,它甚至不需要放入
    this.state
    ,因为这会导致重新渲染。您可能只需要使用实例变量,因为该变量仅对Observables功能至关重要,而不是任何渲染。因此,使用
    this.mouseIsDown
    也同样好

    我们如何处理鼠标下降或上升

    第1部分:

    ...
    Rx.DOM.mousedown(resizerEl)
      .do(() => this.mouseIsDown = true)
    
    当然,最好将其抽象为一个函数,但这是它所做工作的要点

    第2部分:

    ...
    return Rx.DOM.mousemove(tableEl)
      .map(mm => mm.x - md.x)
      .takeUntil(Rx.DOM.mouseup(document))
      .doOnCompleted(() => this.mouseIsDown = false)
    
    在这里,我们利用
    doOnComplete
    在观察对象完成后执行此副作用,在这种情况下,将在
    mouseup
    上执行

    拖动完成后,第二个可观察到的未“完成”(或“重新启动”) 现在有个棘手的问题,我从来没有遇到过这个问题。你看,每次
    Rx.DOM.mousedown(resizerEl)
    发出一个事件,在
    flatMap
    中,每次都会使用
    返回Rx.DOM.mousemove(tabele)…
    创建一个新的可观察对象。我在做这个的时候使用了RxJS 4.1,所以可能会有行为上的差异,但是我发现,仅仅因为内部的可观察完成了,并不意味着外部的也会完成

    那么会发生什么呢?好吧,我想既然您使用了React,那么当组件渲染时,
    resizerEl
    将分别被创建/销毁。当然,我还没有看到您代码的其余部分,但是请纠正我
    ...
    return Rx.DOM.mousemove(tableEl)
      .map(mm => mm.x - md.x)
      .takeUntil(Rx.DOM.mouseup(document))
      .doOnCompleted(() => this.mouseIsDown = false)
    
    if (!this.resizerDrag$ && this.resizer) {
        this.resizerDrag$ = // second Observable from above
      }
      else if (!this.resizer && this.resizerDrag$) {
        this.resizerDrag$ = null;
      }