1

我正在尝试在 codepen 中使用 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

4

1 回答 1

1

测试您的代码表明combine没有获得第一个mousedown事件,显然是由于操作员在第一个 mousedown 事件之后between订阅。mousedown$添加remembermousedown$将第一个 mousedown 事件发送到操作符订阅之间。

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

Codepen.ioremember示例。

Codesandbox.io 测试between


这是另一种 CycleJS/xstream 拖放方法(从这个RxJS 拖放示例中获得灵感)我认为更直接。代码中的其他所有内容基本相同,但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 示例

于 2018-04-08T18:56:49.297 回答