Szukaj…


Wprowadzenie

Zalecany sposób strukturyzacji aplikacji to „Architektura wiązu”.

Najprostszy program składa się z rekordu model przechowującego wszystkie dane, które mogą zostać zaktualizowane, typu unii Msg który definiuje sposób, w jaki program aktualizuje te dane, update funkcji, która pobiera model i Msg i zwraca nowy model oraz view funkcji, który bierze model i zwraca HTML, który wyświetli twoja strona. Za każdym razem, gdy funkcja zwraca Msg , środowisko wykonawcze Elm używa jej do aktualizacji strony.

Program dla początkujących

HTML ma program dla beginnerProgram głównie do celów edukacyjnych.

beginnerProgram nie obsługuje subskrypcji ani nie uruchamia poleceń.

Jest w stanie obsłużyć tylko dane wejściowe użytkownika ze zdarzeń DOM.

Wymaga jedynie view do renderowania model i funkcji update do obsługi zmian stanu.

Przykład

Rozważ ten minimalny przykład programu dla beginnerProgram .

model w tym przykładzie składa się z pojedynczej wartości Int .

Funkcja update ma tylko jedną gałąź, która zwiększa Int , przechowywaną w model .

view renderuje model i dołącza zdarzenie DOM.

Zobacz, jak zbudować przykład w Inicjalizuj i buduj

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 jest dobrym wyborem, gdy aplikacja nie wymaga żadnych danych zewnętrznych do inicjalizacji.

Jest w stanie obsługiwać subskrypcje i polecenia, co zapewnia znacznie więcej możliwości obsługi operacji we / wy, takich jak komunikacja HTTP lub interakcja z JavaScript.

Stan początkowy jest wymagany do zwrócenia poleceń startowych wraz z modelem.

Inicjalizacja program będzie wymagała dostarczenia subscriptions wraz z model , view i update .

Zobacz definicję typu:

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

Przykład

Najprostszym sposobem zilustrowania sposobu korzystania z subskrypcji jest skonfigurowanie prostej komunikacji portu za pomocą JavaScript.

Zobacz, jak zbudować przykład w Inicjalizuj i wbuduj / Osadź w 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 z flagami

programWithFlags ma tylko jedną różnicę od program .

Może zaakceptować dane po inicjalizacji z JavaScript:

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

Dane przekazane z JavaScript nazywa się Flagi.

W tym przykładzie przekazujemy obiekt JavaScript do Elm z informacjami o użytkowniku, dobrą praktyką jest określenie Aliasu typu dla flag.

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

Flagi są przekazywane do funkcji init , tworząc stan początkowy:

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

Możesz zauważyć różnicę w stosunku do podpisu:

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

Kod inicjalizacji wygląda prawie tak samo, ponieważ różni się tylko funkcją init .

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

Jednokierunkowa komunikacja rodzic-dziecko

Przykład pokazuje skład komponentu i jednokierunkowe przekazywanie wiadomości od rodzica do dziecka.

0.18.0

Kompozycja składników opiera się na znakowaniu wiadomości za pomocą Html.App.map

0.18.0

W wersji 0.18.0 HTML.App został zwinięty w HTML

Kompozycja składników opiera się na znakowaniu wiadomości za pomocą Html.map

Przykład

Zobacz, jak zbudować przykład w Inicjalizuj i buduj

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

Oznaczanie wiadomości za pomocą Html.App.map

Komponenty definiują własne wiadomości wysyłane po wysłanych zdarzeniach DOM, np. CounterMsg z komunikacji rodzic-dziecko

type CounterMsg
    = Increment
    | Decrement
    | Reset

Widok tego komponentu wyśle wiadomości typu CounterMsg , dlatego sygnatura typu widoku to Html CounterMsg .

Aby móc ponownie użyć counterView w widoku komponentu nadrzędnego, musimy przekazać każdą wiadomość CounterMsg przez Msg rodzica.

Ta technika nazywa się tagowaniem wiadomości .

Komponent nadrzędny musi zdefiniować komunikaty do przekazywania wiadomości potomnych:

type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll

FirstCounterMsg Increment jest oznaczoną wiadomością.

0.18.0

Aby uzyskać counterView do wysyłania oznaczonych wiadomości, musimy użyć funkcji Html.App.map :

Html.map FirstCounterMsg (counterView model.firstCounter)
0.18.0

Pakiet HTML.App został zwinięty w pakiecie HTML w wersji v0.18.0

Aby uzyskać counterView do wysyłania oznaczonych wiadomości, musimy użyć funkcji Html.map :

Html.map FirstCounterMsg (counterView model.firstCounter)

To zmienia podpis typu Html CounterMsg -> Html Msg dzięki czemu możliwe jest użycie licznika w widoku nadrzędnym i obsługa aktualizacji stanu za pomocą funkcji aktualizacji rodzica.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow