触发事件时获取 ID 属性(elm v0.19.1)

Getting ID attribute when event is triggered (elm v0.19.1)

我有两个 div html 元素(具有 contenteditable 属性),我想在 keypress 时获取元素的 de id 属性被触发(onblur 事件)。

这是我当前的代码(它不起作用,我添加了任何注释):

module Mytest exposing (main)

import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Decode as Json
import Debug

type alias Model =
    { div1 : String
    , div2 : String
    }

initialModel : Model
initialModel =
    { div1 = "test1"
    , div2 = "test2"
    }

init : () -> ( Model, Cmd Msg )
init () =
    ( initialModel, Cmd.none )

view : Model -> Html Msg
view model =
    div []
        [ div [ id "div1", contenteditable True, onKeyPress KeyPressed ] [ text model.div1 ]
        , div [ id "div2", contenteditable True, onKeyPress KeyPressed ] [ text model.div2 ]
        ]

type Msg
    = KeyPressed Int

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        KeyPressed code ->
            let
                -- is there any way to use Debug.log without let block?
                a = Debug.log "div1 event" code
            in
                -- keypressed on div1 should be update div1 field model
                -- the same to div2
                ({model | div1 = String.fromInt code}, Cmd.none)

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

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

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

编辑:

以下示例不会触发 div contenteditable 中的事件:

onInput : (String -> msg) -> Attribute msg
onInput tagger =
    on "input" (Json.map tagger keyCode)

onBlur : (String -> msg) -> Attribute msg
onBlur tagger =
    on "blur" (Json.map tagger targetValue)

onInput : (String -> msg) -> Attribute msg
onInput tagger =
    stopPropagationOn "DOMCharacterDataModified" <|
        Json.map alwaysStop (Json.map tagger (Debug.log "bbb" targetValue))

alwaysStop : a -> (a, Bool)
alwaysStop x =
    (x, True)

但是,在 javascript 中有效:http://jsfiddle.net/MBags/

除非你的例子中没有明显的额外限制,你可以向 KeyPressed 添加一个额外的参数并通过它传递 id:

type Msg
    = KeyPressed String Int

view : Model -> Html Msg
view model =
    div []
        [ div [ id "div1", contenteditable True, onKeyPress (KeyPressed "div1") ] [ text model.div1 ]
        , div [ id "div2", contenteditable True, onKeyPress (KeyPressed "div2") ] [ text model.div2 ]
        ]

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        KeyPressed id code ->
            -- Now you have the id

但是,您可能一开始就不应该依赖字符串 ID,因为字符串类型的数据非常容易出错。理想情况下,每个组件都有单独的 Msg 变体:

type Msg
    = Div1KeyPressed Int
    | Div2KeyPressed Int

或者,如果您需要更多的活力,您可以使用自定义 Id 类型:

type Id
    = Div1
    | Div2

type Msg
    = KeyPressed Id Int

view : Model -> Html Msg
view model =
    div []
        [ div [ contenteditable True, onKeyPress (KeyPressed Div1) ] [ text model.div1 ]
        , div [ contenteditable True, onKeyPress (KeyPressed Div2) ] [ text model.div2 ]
        ]

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        KeyPressed Div1 code ->
            -- update model.div1

        KeyPressed Div2 code ->
            -- update model.div2