Buscar..


Introducción

La forma recomendada de estructurar sus aplicaciones se denomina 'The Elm Architecture'.

El programa más simple consiste en un registro de model almacena todos los datos que pueden actualizarse, un Msg tipo de unión que define las formas en que su programa actualiza esos datos, una update función que toma el modelo y un Msg y devuelve un nuevo modelo, y una view función que toma un modelo y devuelve el HTML que mostrará su página. Cada vez que una función devuelve un Msg , el tiempo de ejecución de Elm lo utiliza para actualizar la página.

Programa de principiante

Html tiene un programa para beginnerProgram principalmente para fines de aprendizaje.

beginnerProgram no es capaz de manejar suscripciones o ejecutar comandos.

Solo es capaz de manejar la entrada del usuario de los eventos DOM.

Solo requiere una view para representar el model y una función de update para manejar los cambios de estado.

Ejemplo

Considere este ejemplo mínimo de beginnerProgram .

El model en este ejemplo consiste en un solo valor Int .

La función de update tiene solo una rama, que incrementa el Int , almacenado en el model .

La view representa el modelo y adjunta el evento DOM.

Vea cómo construir el ejemplo en Inicializar y compilar

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)) ]

Programa

program es una buena opción cuando su aplicación no requiere datos externos para la inicialización.

Es capaz de manejar suscripciones y comandos, lo que permite muchas más oportunidades para el manejo de E / S, como la comunicación HTTP o la interoperabilidad con JavaScript.

Se requiere que el estado inicial devuelva los Comandos de inicio junto con el Modelo.

La inicialización del program requerirá que se proporcionen subscriptions , junto con el model , la view y la update .

Ver la definición de tipo:

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

Ejemplo

La forma más sencilla de ilustrar cómo puede usar las Suscripciones es configurar una comunicación Port simple con JavaScript.

Vea cómo compilar el ejemplo en Inicializar y compilar / incrustar en 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>

Programa con banderas

programWithFlags tiene una sola diferencia del program .

Puede aceptar los datos en la inicialización de JavaScript:

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

Los datos, pasados ​​de JavaScript se llaman Flags.

En este ejemplo, estamos pasando un objeto de JavaScript a Elm con información del usuario, es una buena práctica especificar un alias de tipo para las marcas.

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

Las banderas se pasan a la función init , produciendo el estado inicial:

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

Es posible que note la diferencia con su tipo de firma:

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

El código de inicialización es casi el mismo, ya que solo la función init es diferente.

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

Comunicación unidireccional entre padres e hijos.

El ejemplo muestra la composición de componentes y el mensaje de una sola vía pasando de padres a hijos.

0.18.0

La composición de componentes se basa en el etiquetado de mensajes con Html.App.map

0.18.0

En 0.18.0 HTML.App fue contraído en HTML

La composición de componentes se basa en el etiquetado de mensajes con Html.map

Ejemplo

Vea cómo construir el ejemplo en Inicializar y construir

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

Etiquetado de mensajes con Html.App.map

Los componentes definen sus propios mensajes, enviados después de los eventos DOM emitidos, por ejemplo. CounterMsg de comunicación padre-hijo

type CounterMsg
    = Increment
    | Decrement
    | Reset

La vista de este componente enviará mensajes de tipo CounterMsg , por lo tanto, la firma del tipo de vista es Html CounterMsg .

Para poder reutilizar counterView vista interior del componente principal, tenemos que pasar todos los CounterMsg mensaje a través de los padres Msg .

Esta técnica se llama etiquetado de mensajes .

El componente principal debe definir mensajes para pasar mensajes secundarios:

type Msg
    = FirstCounterMsg CounterMsg
    | SecondCounterMsg CounterMsg
    | ResetAll

FirstCounterMsg Increment es un mensaje etiquetado.

0.18.0

Para obtener un counterView para enviar mensajes etiquetados, debemos usar la función Html.App.map :

Html.map FirstCounterMsg (counterView model.firstCounter)
0.18.0

El paquete HTML.App se HTML.App en el paquete HTML en v0.18.0

Para obtener un counterView para enviar mensajes etiquetados, debemos usar la función Html.map :

Html.map FirstCounterMsg (counterView model.firstCounter)

Eso cambia el tipo de firma Html CounterMsg -> Html Msg por lo que es posible usar el contador dentro de la vista principal y manejar las actualizaciones de estado con la función de actualización de los padres.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow