Elm Language
De ieparchitectuur
Zoeken…
Invoering
De aanbevolen manier om uw applicaties te structureren wordt 'de ieparchitectuur' genoemd.
De eenvoudigste programma bestaat uit een model registratie opslag van alle data die kunnen worden bijgewerkt, een soort vakbond Msg dat definieert manieren waarop uw programma-updates die gegevens, een functie update die het model en neemt Msg en keert terug een nieuw model, en een functie view die neemt een model en retourneert de HTML die uw pagina zal weergeven. Telkens wanneer een functie een Msg retourneert, gebruikt de Elm-runtime deze om de pagina bij te werken.
Beginner programma
Html heeft beginnerProgram voornamelijk voor leerdoeleinden.
beginnerProgram kan geen abonnementen verwerken of opdrachten uitvoeren.
Het kan alleen gebruikersinvoer van DOM-gebeurtenissen verwerken.
Het vereist alleen een view om het model en een update om statuswijzigingen af te handelen.
Voorbeeld
Beschouw dit minimale voorbeeld van beginnerProgram .
Het model in dit voorbeeld bestaat uit een enkele Int waarde.
De update heeft slechts één tak, die de Int verhoogt, opgeslagen in het model .
De view geeft het model weer en bevestigt de klik op DOM-gebeurtenis.
Zie het voorbeeld bouwen in Initialiseren en bouwen
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)) ]
Programma
program is een goede keuze, wanneer uw toepassing geen externe gegevens nodig heeft voor initialisatie.
Het is in staat om abonnementen en opdrachten af te handelen, waardoor er veel meer mogelijkheden zijn voor het verwerken van I / O, zoals HTTP-communicatie of interop met JavaScript.
De initiële status is vereist om opstartopdrachten samen met het model te retourneren.
De initialisatie van het program vereist dat subscriptions worden verstrekt, samen met het model , view en update .
Zie de typedefinitie:
program :
{ init : ( model, Cmd msg )
, update : msg -> model -> ( model, Cmd msg )
, subscriptions : model -> Sub msg
, view : model -> Html msg
}
-> Program Never
Voorbeeld
De eenvoudigste manier om te illustreren hoe u abonnementen kunt gebruiken, is om een eenvoudige poortcommunicatie met JavaScript in te stellen.
Bekijk hoe u het voorbeeld bouwt in Initialiseren en bouwen / Inbedden in 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>
Programma met vlaggen
programWithFlags heeft slechts één verschil met het program .
Het kan de gegevens accepteren na initialisatie van JavaScript:
var root = document.body;
var user = { id: 1, name: "Bob" };
var app = Elm.Main.embed( root, user );
De gegevens die worden doorgegeven door JavaScript worden vlaggen genoemd.
In dit voorbeeld geven we een JavaScript-object door aan Elm met gebruikersinformatie. Het is een goede gewoonte om een Type Alias voor vlaggen op te geven.
type alias Flags =
{ id: Int
, name: String
}
Vlaggen worden doorgegeven aan de init functie en produceren de initiële status:
init : Flags -> ( Model, Cmd Msg )
init flags =
let
{ id, name } =
flags
in
( Model id name, Cmd.none )
Je merkt misschien het verschil met de typeaanduiding:
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
De initialisatiecode ziet er bijna hetzelfde uit, omdat alleen de init functie anders is.
main =
programWithFlags
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
Unidirectionele communicatie tussen ouder en kind
Voorbeeld toont de samenstelling van componenten en eenrichtingsboodschap van ouder op kinderen.
De samenstelling van de componenten is afhankelijk van het taggen van berichten met Html.App.map
In 0.18.0 HTML.App samengevouwen in HTML
De samenstelling van de componenten is afhankelijk van het taggen van berichten met Html.map
Voorbeeld
Bekijk hoe u het voorbeeld bouwt in Initialiseren en bouwen
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
Berichttagging met Html.App.map
Componenten definiëren hun eigen berichten, verzonden na uitgezonden DOM-gebeurtenissen, bijv. CounterMsg van ouder- CounterMsg
type CounterMsg
= Increment
| Decrement
| Reset
De weergave van deze component verzendt berichten van het type CounterMsg , daarom is de handtekening van het weergavetype Html CounterMsg .
Om counterView in de weergave van de bovenliggende component opnieuw te kunnen gebruiken, moeten we elk CounterMsg bericht doorgeven via de bovenliggende Msg .
Deze techniek wordt berichttagging genoemd.
Bovenliggend onderdeel moet berichten definiëren voor het doorgeven van onderliggende berichten:
type Msg
= FirstCounterMsg CounterMsg
| SecondCounterMsg CounterMsg
| ResetAll
FirstCounterMsg Increment is een bericht met tag.
Om een counterView te krijgen om getagde berichten te verzenden, moeten we de functie Html.App.map :
Html.map FirstCounterMsg (counterView model.firstCounter)
Het HTML.App pakket is samengevouwen in het HTML pakket in v0.18.0
Om een counterView te krijgen om getagde berichten te verzenden, moeten we de functie Html.map :
Html.map FirstCounterMsg (counterView model.firstCounter)
Dat verandert de typeaanduiding Html CounterMsg -> Html Msg zodat het mogelijk is om de teller in de bovenliggende weergave te gebruiken en statusupdates af te handelen met de updatefunctie van de ouder.