【问题标题】:how do I get xstream to combine mouse events?如何让 xstream 组合鼠标事件?
【发布时间】:2018-04-06 13:23:15
【问题描述】:

我正在代码笔中尝试使用 cyclejs 进行拖放。 HTML 5 支持的标准拖动方法似乎不支持对拖动对象移动的限制,所以我使用标准的 mousedown/mousemove/mouseup。它有效,但并非始终如一。即使 debug() 调用显示已收到 mousedown 和 mousemove 事件并且有时会错过 mouseup,combine() 操作似乎也不会触发。也许我对操作的理解不完整或不正确。本文底部提供了指向 codepen 的直接链接。任何帮助表示赞赏!

const xs = xstream.default;
const { run } = Cycle;
const { div, svg, makeDOMDriver } = CycleDOM;

function DragBox(sources) {
  const COMPONENT_NAME = `DragBox`;

  const intent = function({ DOM }) {
    return {
      mousedown$: DOM.select(`#${COMPONENT_NAME}`)
        .events("mousedown")
        .map(function(ev) {
          return ev;
        })
        .debug("mousedown"),
      mousemove$: DOM.select(`#${COMPONENT_NAME}`)
        .events("mousemove")
        .map(function(ev) {
          return ev;
        })
        .debug("mousemove"),
      mouseup$: DOM.select("#container")
        .events("mouseup")
        .map(function(ev) {
          return ev;
        })
        .debug("mouseup")
    };
  };

  const between = (first, second) => {
    return source => first.mapTo(source.endWhen(second)).flatten();
  };

  const model = function({ mousedown$, mousemove$, mouseup$ }) {
    return xs
      .combine(mousedown$, mousemove$)
      .debug("combine")
      .map(([mousedown, mousemove]) => ({
        x: mousemove.pageX - mousedown.layerX,
        y: mousemove.pageY - mousedown.layerY
      }))
      .compose(between(mousedown$, mouseup$))
      .startWith({
        x: 0,
        y: 0
      })
      .debug("model");
  };

  const getStyle = left => top => {
    return {
      style: {
        position: "absolute",
        left: left + "px",
        top: top + "px",
        backgroundColor: "#333",
        cursor: "move"
      }
    };
  };

  const view = function(state$) {
    return state$.map(value =>
      div("#container", { style: { height: "100vh" } }, [
        div(`#${COMPONENT_NAME}`, getStyle(value.x)(value.y), "Move Me!")
      ])
    );
  };

  const actions = intent(sources);
  const state$ = model(actions);
  const vTree$ = view(state$);

  return {
    DOM: vTree$
  };
}

function main(sources) {
  const dragBox = DragBox(sources);

  const sinks = {
    DOM: dragBox.DOM
  };

  return sinks;
}

Cycle.run(main, {
  DOM: makeDOMDriver("#app")
});

https://codepen.io/velociflapter/pen/bvqMGp?editors=1111

【问题讨论】:

标签: javascript drag-and-drop cyclejs xstream-js


【解决方案1】:

Testing your code 表明combine 没有获得第一个mousedown 事件,显然是由于between 运算符在第一个mousedown 事件之后订阅了mousedown$。将 remember 添加到 mousedown$ 会将第一个 mousedown 事件发送到 between 运算符订阅。

mousedown$: DOM.select(`#${COMPONENT_NAME}`)
  .events("mousedown").remember()

Codepen.io remember example.

Codesandbox.io testing between


这是另一种 CycleJS/xstream 拖放方法(从 RxJS Drag and Drop example 获得灵感)我认为更直接。代码中的其他所有内容基本相同,但 model 函数是这样的:

const model = function({ mousedown$, mousemove$, mouseup$ }) {
  return mousedown$.map(md => {
    let startX = md.offsetX, startY = md.offsetY
    return mousemove$.map(mm => {
      mm.preventDefault()
      return {
        x: mm.clientX - startX,
        y: mm.clientY - startY
      }
    }).endWhen(mouseup$)
  }).flatten().startWith({x:0,y:0})
};

这是Codepen.io example

【讨论】:

  • 谢谢指关节.. 是的 - 我不确定你是否看到了我后来的评论,但我也怀疑由于 between() 存在问题。这令人费解,因为至少在我的系统上,有时它可以工作。我查看了 xstream 代码,但它是为速度/紧凑性而编写的,所以我可能无法很好地理解它,无法在这个时候得到修复。感谢您的回答!
  • @JamesFremen 夜间睡眠帮助我意识到将 remember 添加到 mousedown$ 保留了 between 运算符的初始 mousedown 事件。
  • 我也可以在我的环境中重现您的修复。很高兴知道继续前进 - 再次感谢!如果您不习惯流式方法,则相当微妙。不过,回想起来确实是合理的 - 以前的操作员正在消费事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-10
  • 2022-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-01
相关资源
最近更新 更多