如何在Elm中设置焦点?

如何在Elm中设置焦点?

问题描述:

如何将焦点设置在Elm中的Html元素上?我试图在元素上设置autofocus属性,它只设置页面加载的焦点。如何在Elm中设置焦点?

elm-lang/dom包的focus功能用于设置焦点与Task(不使用任何port S或JavaScript的)。

它在内部使用requestAnimationFrame来确保在尝试查找要关注的DOM节点之前呈现任何新的DOM更新。

一个例子使用:

type Msg 
    = FocusOn String 
    | FocusResult (Result Dom.Error()) 

update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
     FocusOn id -> 
      (model, Dom.focus id |> Task.attempt FocusResult) 

     FocusResult result -> 
      -- handle success or failure here 
      case result of 
       Err (Dom.NotFound id) -> 
        -- unable to find dom 'id' 
       Ok() -> 
        -- successfully focus the dom 

Full example on Ellie

+0

注意,这确实* *工作,但我发现,如果元素被动态地添加它可以默默地在意外的时间失败。 – AdrianoFerrari

+0

你有没有失败的例子? – robertjlooby

+0

不幸的是,我现在没有一个可重复的例子。如果我找到另一个,我会回复。总的来说,这绝对是正确的做法,所以我的评论应该被忽略,直到我能找到一个特定的情况:) – AdrianoFerrari

我最近花了不少时间探索这个。不幸的是,我认为现有的elm-html库是不可能的。但是,我想出了一个利用css动画触发事件并将其嵌入到纯js中的黑客技术。

这里是我在Elm使用script节点和style节点进行破解。我认为这很丑陋。

import Html exposing (div, button, text, input, node) 
import Html.Events exposing (onClick) 
import Html.Attributes exposing (type', class) 
import StartApp.Simple 

main = 
    StartApp.Simple.start { model = model, view = view, update = update } 

model = [] 

view address model = 
    -- View now starts with a <style> and <script> (hacky) 
    (node "style" [] [ Html.text style ]) :: 
    (node "script" [] [Html.text script ]) :: 
    (button [ onClick address AddInput ] [ text "Add Input" ]) :: 
    model |> 
    div []  

type Action = AddInput 

update action model = 
    case action of 
    AddInput -> (Html.p [] [input [type' "text", class "focus"] []]) :: model 

-- Use pure string css (hacky) 

style = """ 
.focus { 
    animation-name: set-focus; 
    animation-duration: 0.001s; 
    -webkit-animation-name: set-focus; 
    -webkit-animation-duration: 0.001s; 
} 
@-webkit-keyframes set-focus { 
    0% {color: #fff} 
} 
@keyframes set-focus { 
    0% {color: #fff} 
} 
""" 

-- Cheating by embedding pure javascript... (hacky) 

script = """ 
var insertListener = function(event){ 
if (event.animationName == "set-focus") { 
    event.target.focus(); 
}    
} 
document.addEventListener("animationstart", insertListener, false); // standard + firefox 
document.addEventListener("MSAnimationStart", insertListener, false); // IE 
document.addEventListener("webkitAnimationStart", insertListener, false); // Chrome + Safari 
""" 

解决方法是使用Mutation Observers。插入这个JavaScript无论是在主HTML页面或在你的榆树代码的主要观点:

var observer = new MutationObserver(function(mutations) { 
    mutations.forEach(function(mutation) { 
    handleAutofocus(mutation.addedNodes); 
    }); 
}); 
var target = document.querySelector('body > div'); 
var config = { childList: true, subtree: true }; 
observer.observe(target, config); 

function handleAutofocus(nodeList) { 
    for (var i = 0; i < nodeList.length; i++) { 
    var node = nodeList[i]; 
    if (node instanceof Element && node.hasAttribute('data-autofocus')) { 
     node.focus(); 
     break; 
    } else { 
     handleAutofocus(node.childNodes); 
    } 
    } 
} 

然后通过包括Html.Attributes.attribute "data-autofocus" ""创建HTML元素。