【问题标题】:clojurescript core.async - tell if mouse is down while mouseoverclojurescript core.async - 在鼠标悬停时判断鼠标是否关闭
【发布时间】:2014-12-25 08:04:32
【问题描述】:

我正在寻找一种仅在鼠标按下时才响应鼠标悬停事件的好方法。我正在寻找一种更 core.async 的方式来执行此操作。

我在一个 om 组件中有两个通道:

om/IDidMount
(did-mount [_]
  (let [canvas (q ".tutorial")
        _ref (js/Firebase. "https://conseal.firebaseio.com/scribble")
        ctx (.getContext canvas "2d")
        mouse-down (om/get-state owner :mouse-down)
        mouse-chan (om/get-state owner :mouse-chan)]

    (listen canvas EventType.MOUSEDOWN #(put! mouse-down [:down %]))
    (listen canvas EventType.MOUSEMOVE #(put! mouse-chan [:move %]))

然后我在IWillMount 中有以下go-loop

om/IWillMount
(will-mount [_]
  (let [mouse-down (om/get-state owner :mouse-down)
        mouse-chan (om/get-state owner :mouse-chan) ]
    (go-loop []
      (<! mouse-down)
      (let [[evt-type e] (<! mouse-chan)]
          (.log js/console (str evt-type " we are over " e)))
      (recur))))

上述方法不起作用,因为mousedown 事件不会连续发送。我正在寻找一种core.async 惯用的方式来处理这个问题。

如果我使用 rxjs,我可以这样做:

var mouseDrags = mouseDowns.select(function (downEvent) {
    return mouseMoves.takeUntil(mouseUps).select(function (drag) {
        return functionToGetStuffWeWant(drag);
    });
});

【问题讨论】:

    标签: clojure clojurescript core.async


    【解决方案1】:

    保持您当前的代码结构,一种方法是添加一个鼠标向上通道(或将此与鼠标向下结合到鼠标按钮通道或其他东西中)。

    然后在你的 go 循环中,使用以下逻辑:

    1. mouse-downmouse-channel 读取(使用alt)。如果读取了mouse-channel,则忽略该值并循环(到 1)。如果读取了mouse-down,则跳出循环并继续执行 2。
    2. mouse-upmouse-channel 读取。如果读取到mousechannelwas read, process the current position and loop (to 2). Ifmouse-up`,则跳出内部循环,并循环回1。

    具体来说,您可以执行以下操作(未经测试):

    (go-loop []
      (loop []
        (alt! [mouse-down] down nil ;; stop looping when mouse-down is read
              [mouse-channel] event (recur))) ;; loop until mouse-down
      (loop []
        (alt! [mouse-up] up nil ;; stop looping when mouse-up is read
              [mouse-chan] event ;; process current position
                (do
                  (.log js/console (str evt-type " we are over " event))
                  (recur)))) ;; loop until mouse-up
      (recur)) ;; start the process all over again
    

    为了稳健性,您可能需要在第一个循环中读取mouse-up 和第二个循环中的mouse-down,以防有两个连续的鼠标向上(或鼠标向下)事件。否则,它们可能会不同步。在这两种情况下,只需丢弃值和recur

    另一方面,您可能更喜欢类似于您的 rxjs 示例的方法。在这种情况下,请注意核心 clojure 中的几个 seq 操作(maptake 等)在core.async 中有通道类似物。但是,我不认为take-until 是其中之一。不过,实现您自己的在频道上运行的take-until 版本应该很容易。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-04
      • 2018-09-03
      • 2010-11-15
      • 2014-11-04
      • 2010-10-11
      • 1970-01-01
      • 1970-01-01
      • 2015-04-22
      相关资源
      最近更新 更多