【问题标题】:FRP, angular and global event handlersFRP、角度和全局事件处理程序
【发布时间】:2015-04-05 23:41:55
【问题描述】:

我刚开始使用Bacon.js,它真的很棒。尽管有时我确实很难找到正确的做事方式。例如,我想要一个带有可拖动部分的角度指令。我无耻地选择了某人的jsBin 并尝试将该代码改编为 angular

我正在尝试制作一个包含可调整大小列的表格。所以如果我做这样的事情 在列标题指令中

link: (scope, element, attrs)->
    el = element.find('.column-separator')
    doc = $(document)
    mMove = doc.asEventStream('mousemove')
    startDrag = el.asEventStream('mousedown')
    endDrag = doc.asEventStream('mouseup').takeWhile mMove

    # in this case unlike the example in jsBin I don't care about vertical axis, 
    # only horizontal "X"
    getDelta = (t)-> a = t[1]; b = t[0]; return a-b   

    add = (p1,p2)-> p1 + p2

    draggingDeltas = startDrag.flatMap ->
        return mMove
                .map '.clientX'
                .slidingWindow 2,2
                .map getDelta
                .takeUntil endDrag

    pos = draggingDeltas.scan 0, add
    pos.onValue (pos)-> el.css left: pos+"px"

这有点工作,但现在这个指令将在整个页面上注册“mousemove”和“mouseup”事件。我可能可以添加一些takeWhile 语句,事实上我只是尝试过并没有真正起作用。

我的意思是在 Angular 应用程序中使用像 $(document).asEventStream('click') 这样的全局事件处理程序的模式是什么?

  • 您可以在指令中创建处理程序,然后使用takeWhile, takeUntil,但这只会工作一次,因为流最终会停止。每次需要回复document.click 时都需要重新初始化流吗? 在一堆地方有“文档”级别的事件不是一件坏事吗?如果您编写指令$(document).asEventStream('mouseup') 并使用该指令两百次,那不会创建实际的两百个听众吗?

  • 或者您必须在全局范围内引入这些流变量以供整个应用程序使用,然后在指令中执行mapfilterreduce?但是如果有人打电话给takeUntil 并且流完全停止流动并且不能在应用程序的其他部分使用怎么办?

  • 或者可能在应用程序的顶层监听并为流中的每个值发出 $rootScope 事件,然后在指令或视图中使用ng-bacon's$rootScope.$asEventStream(event)? 这不会使应用程序的响应速度有所降低吗?说是否需要响应“keydown”和“keyup”事件?

谁能给我一个例子,如何在角度指令中使用 FRP(特别是拖放示例将不胜感激)

【问题讨论】:

    标签: javascript angularjs frp rxjs bacon.js


    【解决方案1】:

    我不确定这究竟如何符合 Angular 哲学,但我肯定会只添加一次这些处理程序。

    在全局单例类中:

    var mouseHandler = {
      up: $(document).asEventStream('mouseup'),
      move: $(document).asEventStream('mousemove')  
    } 
    

    在单个组件中,您可以向其中添加处理程序,但请确保始终使用 takeUntil,这样 bacon 只会在实际需要时处理这些事件。

    function dragHandler(element) {
      var start = $(element).asEventStream('mousedown')
      var delta = start.flatMap(function() {
        return mouseHandler.move
          .map('.clientX')
          .slidingWindow(2,2)
          .map(getDelta)
          .takeUntil(mouseHandler.up)
      })
    
      var pos = delta.scan(0, add)
      pos.onValue(function(p) {
        $(element).css({left: p + "px"})
      })
    
      function getDelta(t) { return t[1]-t[0] }
      function add(a,b) { return a+b }
    }
    

    http://jsbin.com/yekojitake/3/edit

    【讨论】:

    • 所以这是使用takeWhiletakeUntil 的问题。让我描述一下。假设我有一个指令,当将鼠标悬停在它上面时会打开一个 div,然后当用户单击任何位置(document.click)时它会关闭 div。这两个操作都由toEventStream 流管理。我可以稍后使用takeUntil,但它会完全停止流,我该如何重新注册流?当我试图从其他人的onValue 中绑定一个toEventStream 时,它不起作用。
    • 我还在某处读到培根无论如何都使用单音。所以在一堆地方注册文档级别的事件是可以的。仍然需要明智地使用它们(使用takeWhiletakeUntil
    • 取消注册的一个好方法是保持“关闭”流。当模块/指令/代码的任何部分正在关闭/被销毁时,该流将获得一个值。您将takeUntil(close)添加到您使用的所有流中,在这种情况下添加它就足够了。
    • 当没有监听器时,bacon什么都不做,所以如果mouseHandler的所有用户都被销毁,bacon对监听器什么都不做。
    猜你喜欢
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-14
    相关资源
    最近更新 更多