【问题标题】:How to listen for both keypress and keydown events in Elm?如何在 Elm 中同时监听 keypress 和 keydown 事件?
【发布时间】:2017-06-06 07:24:36
【问题描述】:

我想在 Elm 中同时收听 keypresskeydown 事件。但如果我有以下内容,则只会监听 keydown 事件:

textarea
    [ onWithOptions "keypress" (Options False True) <| Json.Decode.map KeyPress keyCode
    , onWithOptions "keydown" (Options False True) <| Json.Decode.map KeyDown keyCode
    ] []

如果我将Options 更改为不是preventDefault,那么这两个事件都会被监听。但我需要preventDefault,以免tab键改变焦点。

在 Elm 中有什么方法可以做到这一点?

【问题讨论】:

    标签: elm


    【解决方案1】:

    在 Elm 19 中,要访问按下的键,您可以使用 Browser.Events,它是 Elm Browser library 的一部分。如果你想捕捉什么键被关闭,你可以使用这样的东西:

    import Json.Decode as Decode
    
    type Key
      = Character Char
      | Control String
    
    subscriptions : Model -> Sub Msg
    subscriptions model =
        Browser.Events.onKeyDown keyDecoder
    
    keyDecoder : Decode.Decoder Msg
    keyDecoder =
        Decode.map toKey (Decode.field "key" Decode.string)
    
    
    toKey : String -> Msg
    toKey string =
        case String.uncons string of
            Just ( char, "" ) ->
                PressedLetter char
    
            _ ->
                Control string
    

    改编自here

    【讨论】:

      【解决方案2】:

      Pre Elm 0.19,我推荐你使用elm-lang/keyboard。该软件包使用订阅,并且非常易于使用。可以同时订阅keydown和keyup。

      针对您的具体情况: keydown 事件的默认操作是触发 keypress 事件。如果您阻止该默认行为,您将不会收到按键事件。

      您可以阅读有关 keydown 事件的更多信息here

      也许你只需要使用 keyup 和 keydown。

      希望对你有帮助。

      【讨论】:

      • elm-lang/keyboard 的问题是它不适用于特定的输入元素,我知道...似乎仅适用于整个网页。
      • 是的,但是在您的更新函数中,您可以处理这些事件如何与您的模型交互。我已使用有关您的案例的更多信息编辑了我的答案。
      【解决方案3】:

      docsHParker's answer 的启发,我使用 Elm 0.19 和订阅编写了一个更完整的解决方案。

      它为Browser.Events.onKeyUp/Down 添加了一个订阅,并在带有子消息的顶级消息中处理它们以便于处理。它包括 Alt、Ctrl、Shift 和 Meta(Windows 键/选项)。

      请记住,onKeyUp/DownonKeyPressed 处理字符的方式不同(向上/向下使用适当的大小写,而按下则不使用)。

      import Browser.Events
      import Json.Decode as Decode
      
      
      type KeyEventMsg
          = KeyEventControl
          | KeyEventAlt
          | KeyEventShift
          | KeyEventMeta
          | KeyEventLetter Char
          | KeyEventUnknown String
      
      
      type Msg
          = KeyPressedMsg KeyEventMsg
          | KeyReleasedMsg KeyEventMsg
      
      
      update : Msg -> ( Model, Cmd Msg )
      update msg =
          case msg of
              KeyPressedMsg keyEventMsg ->
                  case keyEventMsg of
                      KeyEventShift ->
                          ( { model | shiftIsPressed = True }, Cmd.none )
      
                      _ ->
                          ( model, Cmd.none )
      
              KeyReleasedMsg keyEventMsg ->
                  case keyEventMsg of
                      KeyEventShift ->
                          ( { model | shiftIsPressed = False }, Cmd.none )
      
                      _ ->
                          ( model, Cmd.none )
      
      
      subscriptions : Model -> Sub Msg
      subscriptions model =
          Sub.batch
              [ Browser.Events.onKeyDown keyPressedDecoder
              , Browser.Events.onKeyUp keyReleasedDecoder
              ]
      
      
      keyPressedDecoder : Decode.Decoder Msg
      keyPressedDecoder =
          Decode.map (toKeyEventMsg >> KeyPressedMsg) (Decode.field "key" Decode.string)
      
      
      keyReleasedDecoder : Decode.Decoder Msg
      keyReleasedDecoder =
          Decode.map (toKeyEventMsg >> KeyReleasedMsg) (Decode.field "key" Decode.string)
      
      
      toKeyEventMsg : String -> KeyEventMsg
      toKeyEventMsg eventKeyString =
          case eventKeyString of
              "Control" ->
                  KeyEventControl
      
              "Shift" ->
                  KeyEventShift
      
              "Alt" ->
                  KeyEventAlt
      
              "Meta" ->
                  KeyEventMeta
      
              string_ ->
                  case String.uncons string_ of
                      Just ( char, "" ) ->
                          KeyEventLetter char
      
                      _ ->
                          KeyEventUnknown eventKeyString
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多