繁体   English   中英

卤素键盘输入示例并取消订阅事件?

[英]Halogen keyboard-input example and unsubsribing to the events?

如何从键盘输入示例中的 HandleKey 以外的其他操作取消订阅键盘事件? (问题与 Halogen 2.0.1 版和 purescript 0.11.4 版有关。)

在示例中,输入/返回有效。 我有一组可以通过按下关闭按钮用鼠标折叠的元素,关闭操作会处理它。 此外,输入/返回可用于折叠元素,它可以正常工作。

Open next -> do
  st <- H.get
  if not st.open
    then do
      H.modify (_ { open = true })
      eval (H.action Init)
    else pure unit
  pure next

Close next -> do
  H.modify (_ { open = false })
  st <- H.get
  case st.unsubscribe of
    Nothing -> pure unit
    -- Just smth -> H.liftAff smth
    Just _ -> H.modify (_ { unsubscribe = Nothing}) -- H.liftAff us
  pure next

Init next -> do
  H.modify (_ { open = true})
  document <- H.liftEff $ DOM.window >>= DOM.document <#> DOM.htmlDocumentToDocument
  H.subscribe $ ES.eventSource'
    (K.onKeyUp document)
    (Just <<< H.request <<< HandleKey)
  -- H.modify (_ { unsubscribe = ??? })
  pure next

问题是,当我用鼠标关闭(折叠)元素时,事件侦听器不会被删除(未完成)并且它仍然存在。 当我重新打开元素时,上面的代码将建立第二个(第三个、第四个等)侦听器,然后每个按键都会被多次处理。

我正在考虑创建一个键盘事件,但在这里听起来不是正确的方法。

所以问题是:

  • 如何检查是否已经有键盘监听器?
  • 然后如何在 Close 动作中停止它?
  • 或者是否可以在 Close 操作中制作 Done SubscribeStatus 并将其发送到键盘侦听器?

进一步的问题:

  • 示例在状态中unsubscribe 如何使用它?
  • (我试图在 Init -action 和 Close -action 中放入一些东西,但这纯粹是猜测。)

后期编辑:这似乎与有关动态附加事件侦听器的问题有关,另请参阅thisthisthis

其中一个答案说,只有通过使用状态才能了解动态处理程序,这解决了我的问题。 无论如何,我认为这里提到的问题仍然存在(如何使用 Halogen 删除处理程序,尤其是关于示例中的取消订阅字段 - 它以某种方式可用吗?)

我花了一段时间才理解 eventSource 的签名,但这里有一个细分,可能有助于澄清发生了什么。

这才是真正的签名...

eventSource' :: forall f m a eff. MonadAff (avar :: AVAR | eff) m =>
  ((a -> Eff (avar :: AVAR | eff) Unit) -> Eff (avar :: AVAR | eff) (Eff (avar :: AVAR | eff) Unit)) ->
  (a -> Maybe (f SubscribeStatus)) ->
  EventSource f m

如果我们使用某种伪代码来命名签名的组件......

type Callback a = (a -> Eff (avar :: AVAR | eff) Unit)
type MaybeQuery a = (a -> Maybe (f SubscribeStatus))
type RemoveEventListener = (Eff (avar :: AVAR | eff) Unit)

我们得到...

eventSource' :: forall f m a eff.
  (Callback a -> Eff (avar :: AVAR | eff) RemoveEventListener) ->
  MaybeQuery a ->
  EventSource f m

我认为您缺少的部分是 RemoveEventListener 部分。 下面是 HTMLDocument 上 onMouseUp 的示例 EventSource,它不像您引用的示例那样使用外部函数接口 (FFI)。

import DOM.Event.Types as DET
import DOM.Event.EventTarget as DEET
import DOM.HTML.Event.EventTypes as EventTypes

onMouseUp :: forall e
   . DHT.HTMLDocument
  -> (DET.Event -> Eff (CompEffects e) Unit)
  -> Eff (CompEffects e) (Eff (CompEffects e) Unit)
onMouseUp doc callback = do
  let eventTarget = (DHT.htmlDocumentToEventTarget doc)

  -- Create an EventListener that will log a message
  -- and pass the event to the callback
  let listener =
        DEET.eventListener (\event -> do
          log "mouseUp"
          callback event
        )

  -- Add the EventListener to the
  -- document so it will fire on mouseup
  DEET.addEventListener
    EventTypes.mouseup
    listener true eventTarget

  -- Return the function that will later 
  -- remove the event listener
  pure $ DEET.removeEventListener
    EventTypes.mouseup
    listener true eventTarget

所以回调将获得a事件(在这种情况下是一个通用的Event )。 请注意,我们必须创建对侦听器的引用,因此我们可以将相同的引用传递给 addEventListener 作为 removeEventListener(函数引用的作用就像一个 id 来确定删除哪个侦听器函数)。

MaybeQuery 函数也将传递a事件,因此 Halogen 可以执行查询,您可以决定是否应该继续侦听事件。 该查询将需要像这样结构......

data YourQuery =
  | HandleEvent Event (SubscribeStatus -> a)

eval (HandleEvent event reply) =
  -- Decided if you want to keep listening
  -- or now.

  -- Keep listening...
  -- pure $ reply (H.Listening)

  -- Stop listening.  Halogen will call the removeEventListener
  -- function you returned from onMouseUp earlier
  -- pure $ reply (H.Done)

并展示如何订阅 EventSource ...

import DOM.HTML.Window as Win
import Halogen.Query.EventSource as HES

document <- H.liftEff $ (window >>= Win.document)
H.subscribe $ HES.eventSource'
  (onMouseUp document)
  (Just <<< H.request <<< HandleEvent)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM