如何处理输入字段中的 Enter 键按下?

How to handle Enter key press in input field?

我出于学习目的构建了一个简单的应用程序,并希望能够在用户按下输入字段中的 Enter 键时发送一个操作

view : Model -> Html Action
  view model = 
    let 
      items = List.map (\ item -> li [] [ text item ]) model.items
    in
      div [] [
       input [ onInput Change, value model.content ] [],
       button [ onClick Add ] [ text "Submit" ],
       ul [] items
      ]

这里是查看代码。我希望这足以向您解释我的意图。我想要的是当用户在输入一些文本到输入字段时按下 Enter 键时能够调度一些动作。

您可以使用通用 on 处理程序手动绑定到 keydown 事件。 Elm 目前不支持开箱即用的 onKeyDown 处理程序 - 但他们计划在未来。

It looks like the spec is moving away from event.keyCode and towards event.key. Once this is supported in more browsers, we may add helpers here for onKeyUp, onKeyDown, onKeyPress, etc. (Source)

在那之前,您可以简单地编写自己的处理程序并使用键码 13(回车)来执行您的操作。打开下面的 ellie-app 看看它是如何工作的。 只需在输入框中输入一些文字并回车即可看到输入框下方的div反映的当前状态。

import Html exposing (text, div, input, Attribute)
import Browser
import Html.Events exposing (on, keyCode, onInput)
import Json.Decode as Json


main =
  Browser.sandbox 
  { init = 
    { savedText = ""
    , currentText = ""
    }
  , view = view
  , update = update
  }


view model =
  div [] 
  [ input [onKeyDown KeyDown, onInput Input] []
  , div [] [ text ("Input: " ++ model.savedText) ]
  ]

onKeyDown : (Int -> msg) -> Attribute msg
onKeyDown tagger =
  on "keydown" (Json.map tagger keyCode)


type Msg 
  = NoOp
  | KeyDown Int
  | Input String


update msg model =
  case msg of

    NoOp ->
      model

    KeyDown key ->
      if key == 13 then
        { model | savedText = model.currentText }
      else
        model

    Input text ->
      { model | currentText = text }

您可以在 input 元素中使用类似这样的内容, 如果按下回车键,这将触发给定的消息:

onEnterPressed : msg -> Attribute msg
onEnterPressed msg =
  let
    isEnter code =
      if code == 13 then Ok () else Err ""
    decodeEnterKeyCode = Json.customDecoder keyCode isEnter
  in on "keydown" <| Json.map (\_ -> msg) decodeEnterKeyCode

Elm version of TodoMVC:

中处理 onEnter 有一个很好的直接解决方案
import Html exposing (Attribute)
import Html.Events exposing (keyCode, on)
import Json.Decode as Json

onEnter : Msg -> Attribute Msg
onEnter msg =
    let
        isEnter code =
            if code == 13 then
                Json.succeed msg
            else
                Json.fail "not ENTER"
    in
        on "keydown" (Json.andThen isEnter keyCode)

上面的答案非常好 - 但是存储 每个字母Model 在每个按键上按下 - 并不总是一个好主意。

例如,在我的例子中,我有一个类似于 fileSystem 的结构 - 我想编辑任何名称 - 无论它是如何嵌套的 - 在 doubbleclick 上。我无法通过每次按键 fileSystem 重建视图 。很卡。

我发现最好接收输入值 - 仅当用户按下 Enter..

type Msg =
    | EditingStarted
    | EditingFinished String
    | CancelEdit

input [ whenEnterPressed_ReceiveInputValue EditingFinished, whenEscPressed_CancelOperation CancelEdit, onBlur CancelEdit ] []

update msg model =
    case msg of
        EditingFinished inputValue ->
            { model | name = inputValue }
        CancelEdit -> ...


whenEnterPressed_ReceiveInputValue : (String -> msg) -> H.Attribute msg
whenEnterPressed_ReceiveInputValue tagger =
  let
    isEnter code =
        if code == 13 then
            JD.succeed "Enter pressed"
        else
            JD.fail "is not enter - is this error shown anywhere?!"

    decode_Enter =
        JD.andThen isEnter E.keyCode
  in
    E.on "keydown" (JD.map2 (\key value -> tagger value) decode_Enter E.targetValue)


whenEscPressed_CancelOperation : msg -> H.Attribute msg
whenEscPressed_CancelOperation tagger =
  let
    isESC code =
        if code == 27 then
            JD.succeed "ESC pressed"
        else
            JD.fail "it's not ESC"

    decodeESC =
        JD.andThen isESC E.keyCode
  in
    E.on "keydown" (JD.map (\key -> tagger) decodeESC)

注意:如果您正在进行 time-traveling 调试 - 您将 而不是 看到每个字母在键入时出现。但是一次显示所有文本 - 因为只有一条消息.. 取决于你做什么 - 这可能是个问题。如果没有,享受 :)

我喜欢阿隆的回答并对其进行了一些迭代以创建一个响应 <enter><esc>

的属性
onEscEnter : String -> (String -> msg) -> Attribute msg
onEscEnter originalValue tagger =
    let
        handleKey : Int -> Jdec.Decoder Int
        handleKey code =
            if L.member code [ 13, 27 ] then
                -- Enter (13) or ESC (27)
                Jdec.succeed code
            else
                Jdec.fail "something to ignore"

        combiner : Int -> String -> msg
        combiner keyCode tgtVal =
            if keyCode == 13 then
                tagger tgtVal
            else if keyCode == 27 then
                tagger originalValue
            else
                Debug.crash "onEscEnter"

        keyCodeDecoder : Jdec.Decoder Int
        keyCodeDecoder =
            Jdec.andThen handleKey keyCode
    in
        on "keydown" (Jdec.map2 combiner keyCodeDecoder targetValue)

如果你愿意使用社区包 Html.Events.Extra http://package.elm-lang.org/packages/elm-community/html-extra/latest/Html-Events-Extra#onEnter 这很容易。

(假设您要在按下回车键时发送 Add 消息。)

import Html.Events.Extra exposing (onEnter)

view : Model -> Html Action
  view model = 
    let 
      items = List.map (\ item -> li [] [ text item ]) model.items
    in
      div [] [
       input [ onInput Change, onEnter Add, value model.content ] [],
       button [ onClick Add ] [ text "Submit" ],
       ul [] items
      ]