如何使用Elm 0.19创建SPA? [英] How to create SPA with Elm 0.19?

查看:45
本文介绍了如何使用Elm 0.19创建SPA?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Elm构建SPA并创建三个页面,该页面应显示内容,具体取决于URL.

I am trying to build a SPA with Elm and create three pages, that should show the content, depends on URL.

这三个页面的内容相似,例如 Page.elm :

The content of these three pages are similar, for example Page.elm:

module Page.NotFound exposing (Msg(..), content)

import Html exposing (..)
import Html.Attributes exposing (..)



---- UPDATE ----


type Msg
    = NotFoundMsg


content : Html Msg
content =
    p [] [ text "Sorry can not find page." ]

Main.elm 中,我有以下代码:

module Main exposing (Model, Msg(..), init, main, update, view)

import API.Keycloak as Keycloak exposing (..)
import Browser
import Browser.Navigation as Nav
import Html exposing (..)
import Html.Attributes exposing (..)
import Json.Decode as Decode
import Page.Account as Account
import Page.Home as Home
import Page.NotFound as NotFound
import Route
import Url
import Url.Parser exposing ((</>), Parser, int, map, oneOf, parse, s, string)



---- MODEL ----


type alias Model =
    { key : Nav.Key
    , url : Url.Url
    , auth : Result String Keycloak.Struct
    }


init : Decode.Value -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init flags url key =
    ( Model key url (Keycloak.validate flags), Cmd.none )



---- ROUTE ----


type Route
    = Account



---- UPDATE ----


type Msg
    = PageNotFound NotFound.Msg
    | PageAccount Account.Msg
    | PageHome Home.Msg
    | LinkClicked Browser.UrlRequest
    | UrlChanged Url.Url


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        LinkClicked urlRequest ->
            case urlRequest of
                Browser.Internal url ->
                    ( model, Nav.pushUrl model.key (Url.toString url) )

                Browser.External href ->
                    ( model, Nav.load href )

        UrlChanged url ->
            ( { model | url = url }
            , Cmd.none
            )



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions _ =
    Sub.none



---- VIEW ----


info : Html Msg
info =
    header [] [ text "Header" ]


createLink : String -> Html Msg
createLink path =
    a [ href ("/" ++ path) ] [ text path ]


navigation : Html Msg
navigation =
    ul []
        [ li [] [ createLink "home" ]
        , li [] [ createLink "account" ]
        ]


content : Model -> Html Msg
content model =
    main_ []
        [ case parse Route.parser model.url of
            Just path ->
                matchedRoute path

            Nothing ->
                NotFound.content
        ]


matchedRoute : Route.Route -> Html Msg
matchedRoute path =
    case path of
        Route.Home ->
            Home.content

        Route.Account ->
            Account.content


body : Model -> List (Html Msg)
body model =
    [ info
    , navigation
    , content model
    ]


view : Model -> Browser.Document Msg
view model =
    { title = "Cockpit"
    , body = body model
    }



---- PROGRAM ----


main : Program Decode.Value Model Msg
main =
    Browser.application
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        , onUrlChange = UrlChanged
        , onUrlRequest = LinkClicked
        }

编译器抱怨:

-- TYPE MISMATCH -------------- /home/developer/Desktop/elm/cockpit/src/Main.elm

The 2nd branch of this `case` does not match all the previous branches:

104|         [ case parse Route.parser model.url of
105|             Just path ->
106|                 matchedRoute path
107|
108|             Nothing ->
109|                 NotFound.content
                     ^^^^^^^^^^^^^^^^
This `content` value is a:

    Html NotFound.Msg

But all the previous branches result in:

    Html Msg

Hint: All branches in a `case` must produce the same type of values. This way,
no matter which branch we take, the result is always a consistent shape. Read
<https://elm-lang.org/0.19.0/union-types> to learn how to "mix" types.

-- TYPE MISMATCH -------------- /home/developer/Desktop/elm/cockpit/src/Main.elm

Something is off with the 2nd branch of this `case` expression:

120|             Account.content
                 ^^^^^^^^^^^^^^^
This `content` value is a:

    Html Account.Msg

But the type annotation on `matchedRoute` says it should be:

    Html Msg

-- TYPE MISMATCH -------------- /home/developer/Desktop/elm/cockpit/src/Main.elm

Something is off with the 1st branch of this `case` expression:

117|             Home.content
                 ^^^^^^^^^^^^
This `content` value is a:

    Html Home.Msg

But the type annotation on `matchedRoute` says it should be:

    Html Msg
Detected errors in 1 module.

我知道类型错误,但不知道如何证明.

I know that the type is wrong, but do not know, how to prove it.

我如何使它工作?

我还查看了 https:中的示例://github.com/rtfeldman/elm-spa-example/blob/master/src/Main.elm ,但无法弄清楚它是如何工作的.

I also looked at the example from https://github.com/rtfeldman/elm-spa-example/blob/master/src/Main.elm but could not figure, how does it work.

推荐答案

您有多种 Msg 类型,可以,但是会导致混淆.简而言之: Main.Msg NotFound.Msg 的类型不同.

You have multiple Msg types, which is OK, but it can lead to confusion. In short: Main.Msg is not the same type as NotFound.Msg.

函数 matchedRoute 返回 HTML Main.Msg ,而函数 NotFound.content 返回 HTML NotFound.Msg ;完全不同的类型.

The function matchedRoute returns a Html Main.Msg while the function NotFound.content returns a Html NotFound.Msg; completely different types.

您已经完成了99%的工作,因为您有一个 PageNotFound NotFound.Msg 类型构造函数,该构造函数会生成 Main.Msg .这使您可以将 NotFound.Msg 包裹在 Main.Msg 中.应该在您的 Nothing-> 分支中执行 PageNotFound NotFound.content .

You're already 99% of the way there because you have a PageNotFound NotFound.Msg type constructor which produces a Main.Msg. This allows you to wrap the NotFound.Msg in a Main.Msg. It should be a matter of doing PageNotFound NotFound.content in your Nothing -> branch.

这篇关于如何使用Elm 0.19创建SPA?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆