Ricerca…


introduzione

Il metodo consigliato per strutturare le tue applicazioni è soprannominato 'Elm Architecture.'

Il programma più semplice consiste in un record di model memorizza tutti i dati che potrebbero essere aggiornati, un Msg tipo union che definisce i modi in cui il programma aggiorna i dati, un update funzione che prende il modello e un Msg e restituisce un nuovo modello e una view funzione che prende un modello e restituisce il codice HTML che la pagina mostrerà. Ogni volta che una funzione restituisce un Msg , il runtime Elm lo utilizza per aggiornare la pagina.

Programma per principianti

Html ha beginnerProgram principalmente per scopi di apprendimento.

beginnerProgram non è in grado di gestire abbonamenti o comandi in esecuzione.

È solo in grado di gestire l'input dell'utente dagli eventi DOM.

Richiede solo una view per rendere il model e una funzione di update per gestire le modifiche di stato.

Esempio

Considera questo esempio minimale di beginnerProgram .

Il model in questo esempio è costituito da un singolo valore Int .

La funzione di update ha solo un ramo, che incrementa l' Int , memorizzato nel model .

La view esegue il rendering del modello e allega clic su Evento DOM.

Guarda come costruire l'esempio in Inizializza e crea

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 è una buona scelta, quando l'applicazione non richiede dati esterni per l'inizializzazione.

È in grado di gestire abbonamenti e comandi, il che consente maggiori opportunità per la gestione degli I / O, come la comunicazione HTTP o l'interoperabilità con JavaScript.

Lo stato iniziale è necessario per restituire comandi di avvio insieme al modello.

L'inizializzazione del program richiederà la subscriptions di subscriptions , insieme al model , alla view e update .

Vedi la definizione del tipo:

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

Esempio

Il modo più semplice per illustrare come utilizzare le Iscrizioni è impostare una semplice comunicazione Port con JavaScript.

Scopri come creare l'esempio in Inizializza e crea / Incorporamento 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 con le bandiere

programWithFlags ha una sola differenza dal program .

Può accettare i dati al momento dell'inizializzazione da JavaScript:

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

I dati, passati da JavaScript, sono chiamati Flags.

In questo esempio stiamo passando un oggetto JavaScript a Elm con le informazioni dell'utente, è buona norma specificare un alias di tipo per i flag.

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

Le flag vengono passate alla funzione init , producendo lo stato iniziale:

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

Potresti notare la differenza dalla sua firma di tipo:

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

Il codice di inizializzazione sembra quasi lo stesso, dal momento che è solo la funzione init che è diversa.

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

Comunicazione genitore-figlio a senso unico

L'esempio dimostra la composizione del componente e il messaggio unidirezionale che passa dal genitore ai figli.

0.18.0

La composizione del componente si basa sulla codifica dei messaggi con Html.App.map

0.18.0

In 0.18.0 HTML.App stato collassato in HTML

La composizione dei componenti si basa sulla codifica dei messaggi con Html.map

Esempio

Guarda come costruire l'esempio in Initialise e build

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

Tagging dei messaggi con Html.App.map

I componenti definiscono i propri messaggi, inviati dopo eventi DOM emessi, ad es. CounterMsg dalla comunicazione padre-figlio

type CounterMsg
    = Increment
    | Decrement
    | Reset

La vista di questo componente invierà messaggi di tipo CounterMsg , pertanto la firma del tipo di vista è Html CounterMsg .

Per poter riutilizzare la vista del counterView all'interno della componente del genitore, dobbiamo passare ogni messaggio CounterMsg attraverso il Msg del genitore.

Questa tecnica è chiamata tagging dei messaggi .

Il componente principale deve definire i messaggi per il passaggio dei messaggi secondari:

type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll

FirstCounterMsg Increment è un messaggio con tag.

0.18.0

Per ottenere una counterView per inviare messaggi con tag, dobbiamo utilizzare la funzione Html.App.map :

Html.map FirstCounterMsg (counterView model.firstCounter)
0.18.0

Il pacchetto HTML.App è stato compresso nel pacchetto HTML in v0.18.0

Per ottenere una counterView per inviare messaggi con tag, dobbiamo utilizzare la funzione Html.map :

Html.map FirstCounterMsg (counterView model.firstCounter)

Ciò modifica la firma del tipo Html CounterMsg -> Html Msg modo che sia possibile utilizzare il contatore all'interno della vista genitore e gestire gli aggiornamenti di stato con la funzione di aggiornamento del genitore.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow