2015-08-09 112 views

回答

40

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

4

我最近花了不少時間探索這個。不幸的是,我認爲現有的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 
""" 
9

解決方法是使用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元素。