我正在使用现有的 Rails 应用程序,其中导航必须继续在后端构建(由于复杂性和时间限制)。预期结果是使用 Elm 生成一些页面,使用 Rails 生成一些页面,不使用哈希值,并且不重新加载整个页面(至少对于 Elm 页面)。简化版的导航如下所示:
<nav>
<a href="rails-page-1">...
<a href="rails-page-2">...
<a href="elm-page-1">...
<a href="elm-page-2">...
</nav>
<div id="elm-container"></div>
我已经尝试过 Elm 导航包和 elm-route-url,可能接近后者,除非我从根本上误解了该包的功能。
有办法做到这一点吗?我已经使用哈希标签让它工作了,但是没有它们就没有运气。
使用哈希标签
好吧,你让我笑了。
我的
Helpers.elm
文件中有这个人,我可以用它来代替 Html.Events.click
。
{-| Useful for overriding the default `<a>` behavior which
causes a refresh, but can be used anywhere
-}
overrideClick : a -> Attribute a
overrideClick =
Decode.succeed
>> onWithOptions "click"
{ stopPropagation = False
, preventDefault = True
}
因此,在
a [ overrideClick (NavigateTo "/route"), href "/route" ] [ text "link" ]
上,将允许中键单击元素以及使用推送状态来更新导航。
您需要的是在 JavaScript 上与 pushState 配合使用的类似功能,并且您不想破坏中键单击体验。您可以劫持其事件上的所有
<a>
、preventDefault
以阻止浏览器导航,并通过目标的 href 推送新状态。您可以在事件处理程序中委托导航的 <a>
。由于 Navigation
运行时不支持从外部侦听历史记录更改(相反,它似乎使用效果管理器),因此您必须通过端口推送该值 - 幸运的是,如果您使用的是 Navigation
包裹,你应该已经有了这些碎片。
UrlParser.parsePath
与 Navigation
程序 之一结合使用。创建一个端口以使用与其内部 URL 更改相同的消息进行订阅。
import Navigation exposing (Location)
port externalPush : (Location -> msg) -> Sub msg
type Msg
= UrlChange Location
# | ...
main =
Navigation.program UrlChange
{ # ...
, subscriptions : \_ -> externalPush UrlChange
}
页面加载后,使用此:
const hijackNavClick = (event) => {
// polyfill `matches` if needed
if (event.target.matches("a[href]")) {
// prevent the browser navigation
event.preventDefault()
// push the new url
window.history.pushState({}, "", event.target.href)
// send the new location into the Elm runtime via port
// assuming `app` is the name of `Elm.Main.embed` or
// whatever
app.ports.externalPush.send(window.location)
}
}
// your nav selector here
const nav = document.querySelector("nav")
nav.addEventListener("click", hijackNavClick, false)
(此内容可在 CC-BY-SA-4.0 下使用,且不得用于闭源 LLM 培训)