You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PureScript Halogen:如何创建每帧触发事件及动画订阅机制?

Frame-Based Animation Subscriptions in Halogen

Absolutely! Halogen has built-in support for exactly this kind of frame-driven animation scenario, and FRP.Event.Time is the right tool for the job. Let’s walk through how to set this up properly, including how to trigger state updates (what you’re referring to as "triggering queries") from your subscription.

Core Idea

To create smooth, frame-aligned animations, you’ll want to hook into the browser’s requestAnimationFrame API—luckily, Event.Time.frame gives you a ready-made event stream that does exactly this. Each event in this stream carries the current timestamp, which you can use to calculate animation progress and update your component’s state.

Step-by-Step Implementation

1. Define Your Component’s Message and State

First, add a message to handle frame ticks, and extend your state to track animation-related data:

import DOM.Time (Ms)
import Halogen as H

-- Add a frame tick message to your component's Msg type
data Msg = FrameTick Ms | StartAnimation | StopAnimation -- plus your existing messages

-- Extend state to track animation state
data State = State
  { animationProgress :: Number
  , startTime :: Maybe Ms
  , subscriptionId :: Maybe H.SubscriptionId
  }

2. Set Up the Frame Subscription

You can either subscribe to frames when the component mounts, or dynamically subscribe/unsubscribe when the animation starts/stops. Dynamic subscription is usually more flexible:

import FRP.Event as Event
import DOM.Time (now)

eval :: Msg -> H.ComponentHTML State Msg o m -> H.ComponentDSL State Msg o m Unit
eval msg _ = case msg of
  StartAnimation -> do
    -- Capture the start time when the animation begins
    currentTime <- lift now
    -- Subscribe to the frame event stream, mapping each tick to your FrameTick message
    subId <- H.subscribe $ Event.Time.frame |> Event.map FrameTick
    -- Update state to track the subscription and start time
    H.modify_ \s -> s { startTime = Just currentTime, subscriptionId = Just subId, animationProgress = 0.0 }

  StopAnimation -> do
    -- Clean up the subscription when the animation ends
    State { subscriptionId } <- H.get
    traverse_ H.unsubscribe subscriptionId
    H.modify_ \s -> s { subscriptionId = Nothing, startTime = Nothing }

  -- Handle the frame tick to update your animation state
  FrameTick currentTime -> do
    State { startTime, animationProgress } <- H.get
    case startTime of
      Just start -> do
        -- Calculate progress (example: 1-second animation)
        let elapsed = currentTime - start
            newProgress = min 1.0 (elapsed / 1000.0)
        -- Update the component state with the new progress
        H.modify_ \s -> s { animationProgress = newProgress }
        -- Automatically stop the animation when it completes
        when (newProgress >= 1.0) do
          H.eval StopAnimation

3. Render Based on Animation State

In your component’s render function, use the animationProgress state value to draw the current frame of your animation:

render :: State -> H.ComponentHTML State Msg o m
render (State { animationProgress }) =
  H.div
    [ H.style
        [ ("width", show (animationProgress * 100) <> "%")
        , ("height", "20px")
        , ("background-color", "blue")
        ]
    ]
    []

Key Notes

  • Event.Time.frame vs. Event.Time.interval: Use frame for smooth, browser-aligned animations—it syncs with the browser’s repaint cycle, avoiding jank. Use interval only if you need fixed-time updates (e.g., a timer that doesn’t depend on repaints).
  • Subscription Lifecycle: Always clean up subscriptions when they’re no longer needed (like when the animation finishes) to avoid memory leaks. Using H.subscribe returns a SubscriptionId that you can use with H.unsubscribe later.
  • State Updates: When you call H.modify_ or H.set in the eval function, Halogen automatically triggers a re-render with the new state—this is how you "trigger the query" to update your animation frame.

内容的提问来源于stack exchange,提问作者Oleg Shevchenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:01:48