标记

标记是在初始化时将值传递到 Elm 的一种方式。

常见用途包括传递 API 密钥、环境变量和用户数据。如果您动态生成 HTML,这会很方便。它们还可以帮助我们在此 localStorage 示例 中加载缓存信息。

HTML 中的标记

HTML 与之前基本相同,但向 Elm.Main.init() 函数添加了一个 flags 参数

<html>
<head>
  <meta charset="UTF-8">
  <title>Main</title>
  <script src="main.js"></script>
</head>

<body>
  <div id="myapp"></div>
  <script>
  var app = Elm.Main.init({
    node: document.getElementById('myapp'),
    flags: Date.now()
  });
  </script>
</body>
</html>

在此示例中,我们传递的是以毫秒为单位的当前时间,但任何可以 JSON 编码的 JS 值都可以作为标记提供。

注意:这些附加数据称为“标记”,因为它有点儿像命令行标记。您可以调用 elm make src/Main.elm,但可以添加一些标记,例如 --optimize--output=main.js,以自定义其行为。同样的大致意思。

Elm 中的标记

要在 Elm 侧处理标记,您需要对 init 函数稍加修改

module Main exposing (..)

import Browser
import Html exposing (Html, text)


-- MAIN

main : Program Int Model Msg
main =
  Browser.element
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }


-- MODEL

type alias Model = { currentTime : Int }

init : Int -> ( Model, Cmd Msg )
init currentTime =
  ( { currentTime = currentTime }
  , Cmd.none
  )


-- UPDATE

type Msg = NoOp

update : Msg -> Model -> ( Model, Cmd Msg )
update _ model =
  ( model, Cmd.none )


-- VIEW

view : Model -> Html Msg
view model =
  text (String.fromInt model.currentTime)


-- SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions _ =
  Sub.none

这里唯一重要的是 init 函数表明它采用一个 Int 参数。这就是 Elm 代码如何立即访问您从 JavaScript 中传递的标记的方式。在此基础上,您可以将内容放在模型中或运行某些命令。无论您需要做什么都可以。

我建议查看 localStorage 示例,以了解标记的更有趣用法!

验证标记

但是,如果 init 表明它采用一个 Int 标记,但有人尝试使用 Elm.Main.init({ flags: "haha, what now?" }) 进行初始化,会怎样?

Elm 会检查此类内容,以确保标记完全符合您的预期。如果没有此检查,您可以传入任何内容,从而导致 Elm 中出现运行时错误!

有一些类型可以作为标记提供

很多人经常使用 Json.Decode.Value,因为它能让他们拥有精准的控制。他们可以用 Elm 代码编写一个解码器来处理任何出错的情况,能很好地从意外数据中恢复过来。

其他受支持的类型实际上早于我们找到 JSON 解码器的方法时就已经有了。如果您选用它们,有一些细微之处需要了解。以下示例展示了期望的标志类型,接下来的小节则展示了如果使用两个不同的 JS 值会发生什么

  • init : Int -> ...

    • 0 => 0
    • 7 => 7
    • 3.14 => error
    • 6.12 => error
  • init : Maybe Int -> ...

    • null => Nothing
    • 42 => Just 42
    • "hi" => error
  • init : { x : Float, y : Float } -> ...

    • { x: 3, y: 4, z: 50 } => { x = 3, y = 4 }
    • { x: 3, name: "Tom" } => error
    • { x: 360, y: "why?" } => error
  • init : (String, Int) -> ...

    • ["Tom", 42] => ("Tom", 42)
    • ["Sue", 33] => ("Sue", 33)
    • ["Bob", "4"] => error
    • ["Joe", 9, 9] => error

请注意,当某个转换出错时,您将在 JS 侧遇到错误!我们采取了“尽早失败”策略。错误不会进入 Elm 代码,而是在及早阶段报告。这也是人们喜欢对标志使用 Json.Decode.Value 的另一个原因。异常值会通过解码器,而不是在 JS 中遇到错误,这可以确保您实施某种回退行为。

个与 "" 相匹配的结果

    没有与 "" 相匹配的结果