如何取消订阅keyboard-input example中除HandleKey以外的其他操作的键盘事件? (该问题与卤素版本2.0.1和purescript 0.11.4有关。)
在示例中,输入/返回有效。我有一组元素可以通过按下关闭按钮用鼠标折叠,而Close-action可以处理它。此外,输入/返回可用于折叠元素,它可以正常工作。
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
问题是,当我用鼠标关闭(折叠)元素时,事件监听器不会被删除(不完成),它仍然会存在。当我重新打开元素时,上面的代码将建立第二个(第三个,第四个等)监听器,然后每个按键将被处理多次。
我正在考虑创建一个键盘事件,但它在这里听起来并不正确。
所以问题是:
进一步的问题:
unsubscribe
。如何使用它? 延迟编辑: 这似乎与dynamically attached event listeners的问题有关,另请参阅this,this和this。
其中一个答案说,只有通过使用状态才能了解动态处理程序,这对我的问题起了作用。无论如何,我认为这里陈述的问题仍然存在(如何删除Halogen的处理程序,特别是关于示例中的取消订阅字段 - 它是否有用?)
答案 0 :(得分:1)
我花了一些时间来了解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
因此Callback将获得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)