Elm Language
Архитектура вяза
Поиск…
Вступление
Рекомендуемый способ структурирования ваших приложений называется «Elm Architecture».
Простейшая программа состоит из model записи , хранящего все данные , которые могут быть обновлены, тип союза Msg , который определяет пути ваша программа обновляет эти данные, функция update , которая принимает модель и Msg и возвращает новую модель, и функция view , которая берет модель и возвращает HTML, который отобразит ваша страница. Каждый раз, когда функция возвращает Msg , среда выполнения Elm использует ее для обновления страницы.
Программа для начинающих
Html имеет beginnerProgram основном для учебных целей.
beginnerProgram не может обрабатывать Подписки или выполняемые команды.
Он способен обрабатывать только пользовательский ввод событий DOM.
Это требует только view для отображения model и функции update для обработки изменений состояния.
пример
Рассмотрим этот минимальный пример beginnerProgram .
model в этом примере состоит из одного значения Int .
Функция update имеет только одну ветвь, которая увеличивает Int , сохраненную в model .
view отображает модель и присоединяется к событию DOM.
Посмотрите, как построить пример в Initialize and build
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 - хороший выбор, когда ваше приложение не требует каких-либо внешних данных для инициализации.
Он способен обрабатывать Subscriptions и Commands, что позволяет использовать больше возможностей для обработки ввода-вывода, таких как HTTP-связь или взаимодействие с JavaScript.
Начальное состояние требуется для возврата команд запуска вместе с моделью.
Для инициализации program потребуются subscriptions , а также model , view и update .
См. Определение типа:
program :
{ init : ( model, Cmd msg )
, update : msg -> model -> ( model, Cmd msg )
, subscriptions : model -> Sub msg
, view : model -> Html msg
}
-> Program Never
пример
Самый простой способ проиллюстрировать, как вы можете использовать Подписки, - это настроить простую связь с портами с помощью JavaScript.
Посмотрите, как создать пример в Initialize и build / Embedding в 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>
Программа с флагами
programWithFlags имеет только одно отличие от program .
Он может принимать данные при инициализации из JavaScript:
var root = document.body;
var user = { id: 1, name: "Bob" };
var app = Elm.Main.embed( root, user );
Данные, переданные из JavaScript, называются флагами.
В этом примере мы передаем объект JavaScript в Elm с информацией о пользователе, это хорошая практика, чтобы указать псевдоним типа для флагов.
type alias Flags =
{ id: Int
, name: String
}
Флаги передаются функции init , создавая начальное состояние:
init : Flags -> ( Model, Cmd Msg )
init flags =
let
{ id, name } =
flags
in
( Model id name, Cmd.none )
Вы можете заметить отличие от его подписи типа:
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
Код инициализации выглядит почти таким же, поскольку это только функция init которая отличается.
main =
programWithFlags
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
Одностороннее сообщение родитель-ребенок
Пример демонстрирует состав компонентов и одностороннее сообщение, передаваемое от родителя к детям.
Компонентный состав зависит от тегов сообщений с помощью Html.App.map
пример
Посмотрите, как создать пример в Initialise и 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
Пометка тегов с помощью Html.App.map
Компоненты определяют свои собственные сообщения, отправленные после испущенных событий DOM, например. CounterMsg из сообщения « Родитель-ребенок»
type CounterMsg
= Increment
| Decrement
| Reset
Представление этого компонента отправит сообщения типа CounterMsg , поэтому сигнатура типа вида - Html CounterMsg .
Чтобы иметь возможность повторно использовать представление counterView внутри родительского компонента, нам нужно передать каждое сообщение CounterMsg через Msg родителя.
Этот метод называется тегами сообщений .
Родительский компонент должен определять сообщения для передачи дочерних сообщений:
type Msg
= FirstCounterMsg CounterMsg
| SecondCounterMsg CounterMsg
| ResetAll
FirstCounterMsg Increment - это помеченное сообщение.
Чтобы получить counterView для отправки помеченных сообщений, мы должны использовать функцию Html.App.map :
Html.map FirstCounterMsg (counterView model.firstCounter)
Пакет HTML.App был HTML.App пакет HTML в v0.18.0
Чтобы получить counterView для отправки помеченных сообщений, мы должны использовать функцию Html.map :
Html.map FirstCounterMsg (counterView model.firstCounter)
Это изменяет подпись типа Html CounterMsg -> Html Msg поэтому можно использовать счетчик внутри родительского представления и обрабатывать обновления состояния с помощью функции обновления родителя.