Sök…


Introduktion

Det rekommenderade sättet att strukturera dina applikationer kallas 'Elm Architecture'.

Den enklaste Programmet består av en model register att lagra alla data som kan uppdateras, en union typ Msg som definierar hur dina programuppdateringar som data, en funktion update som tar modellen och en Msg och returnerar en ny modell, och en funktion view som tar en modell och returnerar HTML som din sida kommer att visa. När en funktion returnerar en Msg , använder Elm-körtiden den för att uppdatera sidan.

Nybörjarprogram

Html har beginnerProgram främst för inlärningsändamål.

beginnerProgram inte hantera prenumerationer eller köra kommandon.

Det kan bara hantera användarinmatning från DOM-händelser.

Det kräver endast en view att återge model och en update att hantera tillståndsändringar.

Exempel

Tänk på detta minimala exempel på beginnerProgram .

model i detta exempel består av ett enda Int värde.

update har bara en gren, som ökar Int , lagrad i model .

view gör modellen och bifogar klick på DOM-händelse.

Se hur du bygger exemplet i Initiera och bygg

import Html exposing (Html, button, text)
import Html exposing (beginnerProgram)
import Html.Events exposing (onClick)


main : Program Never
main =
    beginnerProgram { model = 0, view = view, update = update }


-- UPDATE


type Msg
    = Increment

update : Msg -> Int -> Int
update msg model =
    case msg of
        Increment ->
            model + 1


-- VIEW


view : Int -> Html Msg
view model =
    button [ onClick Increment ] [ text ("Increment: " ++ (toString model)) ]

Program

program är ett bra val när din ansökan inte kräver några externa data för initiering.

Den kan hantera prenumerationer och kommandon, vilket gör det möjligt för fler möjligheter att hantera I / O, till exempel HTTP-kommunikation eller interop med JavaScript.

Det initiala tillståndet krävs för att returnera startkommandon tillsammans med modellen.

Initieringen av program kommer att kräva att subscriptions tillhandahålls, tillsammans med model , view och update .

Se typdefinitionen:

program :
    { init : ( model, Cmd msg )
    , update : msg -> model -> ( model, Cmd msg )
    , subscriptions : model -> Sub msg
    , view : model -> Html msg
    }
    -> Program Never

Exempel

Det enklaste sättet att illustrera hur du kan använda prenumerationer är att installera en enkel port kommunikation med JavaScript.

Se hur du bygger exemplet i Initiera och bygga / Bädda in i HTML

port module Main exposing (..)

import Html exposing (Html, text)
import Html exposing (program)


main : Program Never
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


port input : (Int -> msg) -> Sub msg


-- MODEL


type alias Model =
    Int


init : ( Model, Cmd msg )
init =
    ( 0, Cmd.none )


-- UPDATE


type Msg = Incoming Int


update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
    case msg of
        Incoming x ->
          ( x, Cmd.none )


-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    input Incoming


-- VIEW


view : Model -> Html msg
view model =
    text (toString model)
<!DOCTYPE html>
<html>
    <head>
        <script src='elm.js'></script>
</head>
    <body>
    <div id='app'></div>
    <script>var app = Elm.Main.embed(document.getElementById('app'));</script>
    <button onclick='app.ports.input.send(1);'>send</button>
</body>
</html>

Program med flaggor

programWithFlags har bara en skillnad från program .

Den kan acceptera uppgifterna vid initialisering från JavaScript:

var root = document.body;
var user = { id: 1, name: "Bob" };
var app = Elm.Main.embed( root, user );

Uppgifterna, som skickas från JavaScript kallas Flags.

I det här exemplet överför vi ett JavaScript-objekt till Elm med användarinformation, det är en bra praxis att ange ett typalias för flaggor.

type alias Flags =
    { id: Int
    , name: String
    }

Flaggor skickas till init funktionen, vilket ger det initiala tillståndet:

init : Flags -> ( Model, Cmd Msg )
init flags =
    let
        { id, name } =
            flags
    in
        ( Model id name, Cmd.none )

Du kanske märker skillnaden från dess typsignatur:

programWithFlags :
    { init : flags -> ( model, Cmd msg )          -- init now accepts flags
    , update : msg -> model -> ( model, Cmd msg )
    , subscriptions : model -> Sub msg
    , view : model -> Html msg
    }
    -> Program flags

Initieringskoden ser nästan densamma ut, eftersom det bara är en init funktion som är annorlunda.

main =
    programWithFlags
        { init = init
        , update = update
        , view = view
        , subscriptions = subscriptions
        }

Ett sätt kommunikation mellan föräldrar och barn

Exempel visar komponentkomposition och envägsmeddelande som övergår från förälder till barn.

0.18.0

Komponentkomposition förlitar sig på meddelandetaggning med Html.App.map

0.18.0

I 0.18.0 HTML.App var kollapsade i HTML

Komponentkomposition förlitar sig på meddelandetaggning med Html.map

Exempel

Se hur du bygger exemplet i Initiera och bygg

module Main exposing (..)

import Html exposing (text, div, button, Html)
import Html.Events exposing (onClick)
import Html.App exposing (beginnerProgram)


main =
    beginnerProgram
        { view = view
        , model = init
        , update = update
        }

{- In v0.18.0 HTML.App was collapsed into HTML
   Use Html.map instead of Html.App.map
-}
view : Model -> Html Msg
view model =
    div []
        [ Html.App.map FirstCounterMsg (counterView model.firstCounter)
        , Html.App.map SecondCounterMsg (counterView model.secondCounter)
        , button [ onClick ResetAll ] [ text "Reset counters" ]
        ]


type alias Model =
    { firstCounter : CounterModel
    , secondCounter : CounterModel
    }


init : Model
init =
    { firstCounter = 0
    , secondCounter = 0
    }


type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll


update : Msg -> Model -> Model
update msg model =
    case msg of
        FirstCounterMsg childMsg ->
            { model | firstCounter = counterUpdate childMsg model.firstCounter }

        SecondCounterMsg childMsg ->
            { model | secondCounter = counterUpdate childMsg model.secondCounter }

        ResetAll ->
            { model
                | firstCounter = counterUpdate Reset model.firstCounter
                , secondCounter = counterUpdate Reset model.secondCounter
            }


type alias CounterModel =
    Int


counterView : CounterModel -> Html CounterMsg
counterView model =
    div []
        [ button [ onClick Decrement ] [ text "-" ]
        , text (toString model)
        , button [ onClick Increment ] [ text "+" ]
        ]


type CounterMsg
    = Increment
    | Decrement
    | Reset


counterUpdate : CounterMsg -> CounterModel -> CounterModel
counterUpdate msg model =
    case msg of
        Increment ->
            model + 1

        Decrement ->
            model - 1

        Reset ->
            0

Meddelandetaggning med Html.App.map

Komponenter definierar sina egna meddelanden, skickade efter utsända DOM-händelser, t.ex. CounterMsg från föräldraskommunikation

type CounterMsg
    = Increment
    | Decrement
    | Reset

Vyn för denna komponent kommer att skicka meddelanden av CounterMsg typ, därför är signaturen för Html CounterMsg .

För att kunna återanvända counterView inuti föräldrakomponentens vy måste vi skicka varje CounterMsg meddelande genom föräldrars Msg .

Denna teknik kallas meddelandetaggning .

Föräldrakomponent måste definiera meddelanden för att vidarebefordra barnmeddelanden:

type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll

FirstCounterMsg Increment är ett taggat meddelande.

0.18.0

För att få en counterView att skicka taggade meddelanden måste vi använda funktionen Html.App.map :

Html.map FirstCounterMsg (counterView model.firstCounter)
0.18.0

HTML.App paketet kollapsades i HTML paketet i v0.18.0

För att få en counterView att skicka taggade meddelanden måste vi använda funktionen Html.map :

Html.map FirstCounterMsg (counterView model.firstCounter)

Det ändrar Html CounterMsg -> Html Msg så det är möjligt att använda räknaren i överordnad vyn och hantera tillståndsuppdateringar med föräldrars uppdateringsfunktion.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow