開篇總結:其實目前無法解決這個bug。
這兩天做項目遇到了這個case,項目需求是打開頁面的時候,input元素自動彈起鍵盤。由於各種方面的考慮,我們希望通過setTimeout延時200毫秒讓input元素focus,demo代碼如下:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>IOS下setTimeout無法觸發focus事件的解決方案</title> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"> </head> <body> <div id="container"> <input id="input-box" type="text" placeholder="click here to focus."> </div> <script> var container = document.getElementById("container"); var input = document.getElementById("input-box"); setTimeout(function () { input.focus(); },200); </script> </body> </html>
- 問題出在哪?
上面的代碼在pc上顯示沒有問題,但是在安卓上也ok,但是在ios上出了問題,input沒有獲得焦點,問題出在哪了?
我通過debug發現,代碼能執行到setTimeout里面,並且input元素也沒有選擇失敗,那我們判斷是input.focus()這句失效了。
- 前人指路
然后我們在stackoverflow上搜到了相關的case:Mobile Safari Autofocus text field
在最高票答案中,來自FastClick團隊的大牛指出了IOS下input的獲取焦點存在這樣的問題:
my colleagues and I found that iOS will only allow focus to be triggered on other elements, from within a function, if the first function in the call stack was triggered by a non-programmatic event. In your case, the call to setTimeout
starts a new call stack, and the security mechanism kicks in to prevent you from setting focus on the input.
翻譯:我和我的同事發現,iOS將只允許在其他元素上綁定函數來觸發focus事件,如果第一個函數調用棧是由非編程觸發的事件(這句不知道怎么翻譯)。在你的案例中,調用setTimeout開始一個新的調用堆棧,IOS的安全機制開始阻止你觸發input元素的focus事件。
github上也有相關的issue:iOS does not show keyboard on .focus()
里面也有人指出:
iOS won't, as far as I can tell from testing, show the keyboard without some kind of user interaction.Trying a setTimeout to load it doesnt work. But setting the focus on another element's onClick event brings it up.
翻譯:據我目前測試所知,如果沒有通過某種用戶交互,iOS不會(觸發focus事件)。用setTimeout試圖觸發focus不工作(setTimeout是延時觸發,非用戶交互的當下觸發focus),但設置另一個元素的onClick事件,就能把focus事件帶起來。
//通過在input以外的其他元素綁定事件可以觸發input元素的focus事件 container.addEventListener("click",function(e){ input.focus(); });
- 解決方案?
目前看來沒有更好的辦法能在iOS下,通過setTimeout調起focus事件,所以只能把setTimeout去掉,從產品設計上避免。
如果你有什么好的解決方案,歡迎留言哦!