在 Elm 中,我如何检测焦点是否将从一组元素中失去?

4
假设我有一个包含多个组件的表单。我想检测从组中失去焦点的情况。因此,应忽略在同一表单上从一个输入聚焦到另一个输入的情况。我该如何实现这一点?
1个回答

12

首先,我们希望能够使用某些属性为组内的每个可聚焦元素进行标记,这样当我们切换元素时就会知道我们是否在同一组中。这可以通过数据属性来实现。

groupIdAttribute groupId =
    Html.Attributes.attribute "data-group-id" groupId

接下来,在 onBlur 事件中,我们需要解码事件负载,以查看 target 是否与获取焦点的relatedTarget有所不同,并报告更改。(请注意,在此处我们通过路径 "dataset","groupId" 引用 data-group-id

decodeGroupIdChanged msg =
    Json.Decode.oneOf
        [ Json.Decode.map2
            (\a b ->
                if a /= b then
                    Just a

                else
                    Nothing
            )
            (Json.Decode.at [ "target", "dataset", "groupId" ] Json.Decode.string)
            (Json.Decode.at [ "relatedTarget", "dataset", "groupId" ] Json.Decode.string)
        , Json.Decode.at [ "target", "dataset", "groupId" ] Json.Decode.string
            |> Json.Decode.andThen (\a -> Json.Decode.succeed (Just a))
        ]
        |> Json.Decode.andThen
            (\maybeChanged ->
                case maybeChanged of
                    Just a ->
                        Json.Decode.succeed (msg a)

                    Nothing ->
                        Json.Decode.fail "no change"
            ) 

现在我们可以创建一个 onGroupLoss 监听器:

onGroupFocusLoss msg =
    Html.Events.on "blur" (decodeGroupIdChanged msg)

然后按照以下方式进行装配:

input [onGroupFocusLoss GroupFocusLoss, groupIdAttribute "a"]

这里是一个示例(注意它是使用 elm-ui 构建的,因此有一些额外的代码。)

https://ellie-app.com/3nkBCXJqjQTa1


3
您可以在祖先元素上使用 focusout 事件处理程序,而不是在每个输入框上单独附加 blur 事件处理程序。 - glennsl
有趣。这打开了其他可能的方法,但我不确定最佳选项是什么。我拥有的是最灵活的(例如,假设您有一个控件,弹出一个不属于同一树的子控件,并且您想在控件组通常失去焦点时触发保存)。如果我们知道所有项目都在同一层次结构中,focusout可以导致更清晰的代码。 - Mark Bolusmjak
那些不会有不同的组ID吗? - glennsl
1
我可以想象出一种UI,其中这种情况不会发生。但这并不意味着它是一个很棒的UI。因此,我的解决方案更加通用。你的解决方案是针对某些使用情况的更好解决方案(这些可能是更好的UI设计示例)。我需要再考虑一下这个问题。 - Mark Bolusmjak
它看起来现在很好,"focusout"只是一个注释或脚注。差异非常微妙,虽然在某些边缘情况下可能会有影响 :) - glennsl
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接