在 Elm 0.19 中使用 Browser.application 时,没有 href 或 href 为空的元素会导致页面重新加载

a elements without href, or with an empty href, causes page reload when using Browser.application in Elm 0.19

空链接,即 a 没有 href 属性或带有 href "" 的元素,如果在 Elm 0.19 中与 Browser.application 一起使用,会导致页面重新加载。

这是一个最小的、完整的和可验证的例子:

module Main exposing (main)

import Browser
import Browser.Navigation
import Html exposing (..)
import Url


type alias Model =
    ()


type Msg
    = UrlRequested Browser.UrlRequest
    | UrlChanged Url.Url


init () _ _ =
    ( (), Cmd.none )


update msg model =
    case msg of
        UrlRequested (Browser.Internal _) ->
            ( model, Cmd.none )

        UrlRequested (Browser.External url) ->
            ( model, Browser.Navigation.load url )

        UrlChanged _ ->
            ( model, Cmd.none )


view model =
    { title = ""
    , body = [ a [] [ text "click to reload" ] ]
    }


main =
    Browser.application
        { init = init
        , view = view
        , update = update
        , subscriptions = \_ -> Sub.none
        , onUrlRequest = UrlRequested
        , onUrlChange = UrlChanged
        }

这是非标准行为,因为用户代理不应将此类链接视为超链接,并且很多代码都依赖于此行为,其中 elm-bulma.

这是因为 Elm 将 onclick 事件侦听器附加到所有 a 元素,以便能够在内部拦截和处理路由。它解析 URL 并将其分类为 InternalExternal,其中空的或省略的 href 显然被视为 External。然后,Elm 将使用通过 onUrlRequest 传递给 Browser.application 的类型构造函数创建一个 'Msg',运行 update 传递此 Msg,这就是我们可以适当拦截和处理。

解决方案是向 update 添加另一个匹配空外部 URL 的模式,我们只是什么都不做,而不是尝试 load 和 URL 作为我们通常会使用其他外部 URLs。关于问题的示例,以下更新的 update 函数应该可以解决问题:

update msg model =
    case msg of
        UrlRequested (Browser.Internal _) ->
            ( model, Cmd.none )

        UrlRequested (Browser.External "") ->
            ( model, Cmd.none )

        UrlRequested (Browser.External url) ->
            ( model, Browser.Navigation.load url )

        UrlChanged _ ->
            ( model, Cmd.none )

另一种只涉及视图功能的解决方案是将 a 元素的属性 target 设置为 _self,在这种情况下 Elm 将不会离开。

elm-browser project.

中有一个关于此问题的未解决问题