如何将事件处理程序添加到 Elm 中的 body 元素?

How can I add event handlers to the body element in Elm?

我正在尝试使用 Html.App.beginnerProgram,我想将事件处理程序(onKeyDown 等)添加到 <body> 元素。

不幸的是,我放入 view 的所有内容都变成了 <body> 的子项。从 view 返回 Html.body 并不能解决问题。此代码:

main = beginnerProgram { model = 0, view = view, update = update }

view model = body [] []

update _ model = model

将生成:

<html>
    <head>...</head>
    <body>
        <body></body>
    </body>
</html>

那么,如何获得 <body> 元素的控制权?

由于 Elm 呈现为 <body/> 的后代,您不能以正常的 Elm 方式(例如 button [ onClick SomeMsg ] [])将事件处理绑定到它。相反,您将不得不使用端口。因为您使用的是端口和订阅,所以您需要使用 Html.App.program 而不是 beginnerProgram

您的端口模块中需要一个端口函数:

port bodyKeyPress : (String -> msg) -> Sub msg

然后您将能够从 javascript:

向该端口发送按键
app.ports.bodyKeyPress.send(...);

这是一个完整的例子:

Main.elm

port module Main exposing (main)

import Html.App as App
import Html exposing (..)

main = App.program
  { init = init
  , update = update
  , view = view
  , subscriptions = subscriptions
  }

type alias Model = { message : String } 

type Msg = BodyKeyPress String

init = { message = "Press some keys: " } ! []

update msg model =
  case msg of
    BodyKeyPress c ->
      { model | message = model.message ++ c } ! []

view model = text model.message

subscriptions _ =
  bodyKeyPress BodyKeyPress

port bodyKeyPress : (String -> msg) -> Sub msg

以及幕后的 html(假设您使用 elm make Main.elm --output=Main.js 构建):

<html>
  <body>
    <script src="Main.js"></script>
    <script>
      var app = Elm.Main.fullscreen();

      document.body.onkeypress = function(e) {
        app.ports.bodyKeyPress.send(String.fromCharCode(e.keyCode));
      };
    </script>
  </body>
</html>

您需要为要发送的每个正文事件创建和处理端口函数。