如何解决我如何完成这个 PureScript pushState 路由示例?
我正在尝试使用 purescript-routing
库在 PureScript 中执行 pushState 路由。为了帮助解决这个问题,我构建了以下最小示例:
module Main where
import Prelude
import Data.Foldable (oneOf)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Effect (Effect)
import Effect.Console (log)
import Flame (Html,QuerySelector(..))
import Flame.Application.NoEffects as FAN
import Flame.HTML.Attribute as HA
import Flame.HTML.Element as HE
import Routing.Match (Match,end,int,lit,root)
import Routing.PushState (makeInterface,matches)
import Signal.Channel (send)
type Model = {
route :: Route
}
data Message = ChangeRoute Route
data Route
= RouteOne
| RouteTwo
| RouteThree Int
| Root
derive instance genericRoute :: Generic Route _
instance showRoute :: Show Route where
show = genericShow
route :: Match Route
route = root *> oneOf
[ Root <$ end,RouteOne <$ lit "route-1" <* end,RouteTwo <$ lit "route-2" <* end,RouteThree <$> (lit "route-3" *> int)
]
init :: Model
init = { route: Root }
update :: Model -> Message -> Model
update model = case _ of
ChangeRoute x -> model { route = x }
view :: Model -> Html Message
view model = HE.main "main" $
[ HE.p_ ("Route: " <> show model.route),HE.ul_
[ HE.li_
[ HE.a [ HA.href "/route-1" ] "route 1"
],HE.li_
[ HE.a [ HA.href "/route-2" ] "route 2"
],HE.li_
[ HE.a [ HA.href "/route-3/123" ] "route 3"
]
]
]
main :: Effect Unit
main = do
nav <- makeInterface
flameChannel <- FAN.mount (QuerySelector "main")
{ init,update,view
}
void $ nav # matches route \oldRoute newRoute -> do
log $ show oldRoute <> " -> " <> show newRoute
send flameChannel [ ChangeRoute newRoute ]
什么有效:
- 路由解析
- 在控制台打印当前路由
什么不起作用:单击 DOM 中的链接由页面加载处理,而不是发送到应用程序的信号。
需要进行哪些代码更改/添加,以便单击链接会导致向 Flame 发送信号,而不是加载浏览器页面?我的一般方法是否正确?
我尝试使用 purescript-routing documentation 和 purescript-routing tests 来理解,但都没有显示完整的示例(包括可点击的 URL)。我也尝试过使用 RoutingPushHalogenClassic PureScript cookbook code,但它似乎不适用于 Flame。
解决方法
这是完成它的一种方式:
module Main where
import Prelude
import Data.Foldable (oneOf)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Maybe (Maybe(..),isNothing)
import Debug.Trace (spy)
import Effect (Effect)
import Effect.Console (log)
import Flame (Html,QuerySelector(..))
import Flame.Application.NoEffects as FAN
import Flame.HTML.Attribute as HA
import Flame.HTML.Element as HE
import Foreign (unsafeToForeign)
import Routing.Match (Match,end,int,lit,root)
import Routing.PushState (PushStateInterface,makeInterface,matches)
import Signal.Channel (Channel,send)
import Web.Event.Event (preventDefault)
type Model
= { navInterface :: PushStateInterface,route :: Route
}
data Message
= ChangeRouteInternal Route
| ChangeRouteExternal Route
data Route
= RouteOne
| RouteTwo
| RouteThree Int
| Root
derive instance genericRoute :: Generic Route _
instance showRoute :: Show Route where
show = genericShow
route :: Match Route
route =
root
*> oneOf
[ Root <$ end,RouteOne <$ lit "route-1" <* end,RouteTwo <$ lit "route-2" <* end,RouteThree <$> (lit "route-3" *> int) <* end
]
init :: PushStateInterface -> Model
init nav = { navInterface: nav,route: Root }
update :: Model -> Message -> Model
update model = case _ of
ChangeRouteInternal x -> spy "ChangeRouteInternal" model { route = x }
ChangeRouteExternal x -> spy "ChangeRouteExternal" model { route = x }
view :: Model -> Html Message
view model =
HE.main "main"
$ [ HE.p_ ("Route: " <> show model.route),HE.ul_
[ HE.li_
[ HE.a (routeAnchorAttributes (ChangeRouteInternal RouteOne)) "route 1"
],HE.li_
[ HE.a (routeAnchorAttributes (ChangeRouteInternal RouteTwo)) "route 2"
],HE.li_
[ HE.a (routeAnchorAttributes (ChangeRouteInternal (RouteThree 123))) "route 3"
]
]
]
where
routeAnchorAttributes = case _ of
ChangeRouteInternal anchorRoute -> [ HA.href (routeToUrl anchorRoute),onClick_ anchorRoute ]
_ -> []
-- Based on keypress example at:
-- https://github.com/easafe/purescript-flame/blob/master/test/Basic/EffectList.purs
onClick_ clickedRoute =
HA.createRawEvent "click"
$ \event -> do
preventDefault event
model.navInterface.pushState (unsafeToForeign {}) (routeToUrl clickedRoute)
pure $ Just (ChangeRouteInternal clickedRoute)
routeToUrl :: Route -> String
routeToUrl = case _ of
Root -> "/"
RouteOne -> "/route-1"
RouteTwo -> "/route-2"
RouteThree n -> "/route-3/" <> (show n)
routeMatch :: Match Route -> Channel (Array Message) -> PushStateInterface -> Effect Unit
routeMatch m chan =
void
<$> matches m \oldRoute newRoute -> do
log $ show oldRoute <> " -> " <> show newRoute
if isNothing oldRoute then
send chan [ ChangeRouteExternal newRoute ]
else
pure unit
main :: Effect Unit
main = do
nav <- makeInterface
flameChannel <-
FAN.mount (QuerySelector "main")
{ init: init nav,update,view
}
routeMatch route flameChannel nav
- 此代码具有单独的
Message
具体类型,用于源自应用程序内部与外部的路由更改,即来自用户在地址栏中键入、从外部链接加载应用程序等。这不是必需的,但我想强调的是,这些情况的逻辑和代码路径是不同的。 -
routeMatch
处理外部路由更改,onClick_
用于内部并使用 Flame 自己的createRawEvent
函数。 - 虽然 Flame 文档不包括点击处理和
preventDefault
,但我确实发现 this test of key capture 在制作onClick_
时非常有帮助。 - 打开开发者工具控制台以查看消息和内部状态变化。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。