是否可以使用在Elm应用程序之外构建的现有导航来驱动Elm应用程序?

sco*_*ots 12 ruby-on-rails elm

我正在使用现有的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>
Run Code Online (Sandbox Code Playgroud)

我已经尝试过使用Elm导航软件包和elm-route-url,可能与后者接近,除非我从根本上误解了软件包的功能.

有没有办法实现这个目标?我已经使用哈希标签工作,但没有它们就没有运气.

toa*_*tal 7

使用哈希标签

好吧,你笑了我一顿.

我在我的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
            }
Run Code Online (Sandbox Code Playgroud)

因此,a [ overrideClick (NavigateTo "/route"), href "/route" ] [ text "link" ]允许在中间单击元素以及使用推送状态来更新导航.

你需要的是类似于与pushState一起使用的JavaScript的东西,你不想破坏中键点击体验.您可以在其事件中劫持所有<a>s preventDefault以阻止浏览器导航,并通过目标的href推入新状态.您可以<a>在事件处理程序中委派导航.由于Navigation运行时不支持从外部监听历史记录更改(而不是使用效果管理器),因此您必须通过端口推送值 - 幸运的是,如果您使用的是Navigation包,那么您应该已经拥有碎片.

在Elm端,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
        }
Run Code Online (Sandbox Code Playgroud)

页面加载后,使用:

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)
Run Code Online (Sandbox Code Playgroud)