如何將焦點設置在Elm中的Html元素上?我試圖在元素上設置autofocus屬性,它只設置頁面加載的焦點。如何在Elm中設置焦點?
34
A
回答
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
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元素。
注意,這確實* *工作,但我發現,如果元素被動態地添加它可以默默地在意外的時間失敗。 – AdrianoFerrari
你有沒有失敗的例子? – robertjlooby
不幸的是,我現在沒有一個可重複的例子。如果我找到另一個,我會回覆。總的來說,這絕對是正確的做法,所以我的評論應該被忽略,直到我能找到一個特定的情況:) – AdrianoFerrari