ios 最新系統bug與解決——微信公眾號中彈出鍵盤再收起時,原虛擬鍵盤位點選事件無效

ZoenLeo發表於2019-03-04

最近ios釋出新版本系統12.1,隨著部分使用者的系統更新,一些問題也漸漸暴露出來。。。

公司使用者反映微信公眾號出現了點選無效的bug!!測試調查發現,只有iphonex、iphone6,ihpone7等部分機型會出現該問題

我當時就是一驚,一般出現在事件上的問題都是疑難雜症。何況是跟鍵盤相關的。

我們都知道在H5端是沒法監控鍵盤的彈出與收起的,resize事件觸發的機型極其有限,何況我在ios中實測沒有觸發,安卓反而可以。因為安卓彈起鍵盤時會修改視窗的大小,但是ios並不會,如果你在ios上設定一個100%高度的body,彈起鍵盤後你會發現這個body是可以上下滾動的,即100%高度的body超出了視窗。

(PS: iphoneX的測試機被拿走了,這是安卓下模擬的ios表現?,總之ios能滾成這樣)

ios下的表現

那麼說問題(可以直接翻到文末看解決方案)

下圖是一個問題描述,當我們彈起鍵盤,並且使用如下的佈局時:

安卓下佈局圖

body高度是100%,modal使用fixed定位,四個方向設定為0,預期的結果應該是兩者都適應視窗大小,彈起鍵盤時自動適應。安卓上與預期相同,ios開啟後出現整個modal和body可以滑動的情況。

ios上一直有個很?的優化,彈出鍵盤時會自動把當前輸入框滾動到可視區域,在安卓中會出現鍵盤遮擋輸入框的問題,需要手動調整,ios扳回一城??。我在專案中為了讓安卓達到同樣的效果也是死了不少腦細胞。

但是!!專案本身在穩定執行半年的情況下,這次開始出現問題了。。。

在ios 12.1 中,機型為iphoneX,當我們聚焦輸入框彈出虛擬鍵盤,然後點選鍵盤收起。出現瞭如下的效果圖,並且下半部分做點選事件無效。

ios下bug圖

從現象中找問題,在虛擬鍵盤被收起的情況下,可以看到modal框檢視正常得彈回了,但是仔細看看透明區域下,body檢視還處在鍵盤彈起時的狀態。what fuck? 然後modal下面的可操作區域始終點選無效。。。。

Why?

推測是body沒有正確重新渲染,導致點選事件不處於body內而無法觸發。

(簡陋推測圖......)

推測圖

How?

那麼怎麼解決呢,是不是隻要把body‘推’會來就行了? 方向有了,現在是如何‘推’的問題。

上文有說過,ios下彈出/收起鍵盤是沒有觸發resize事件的,那麼在什麼節點觸發‘推’的操作就成了問題。

這時候封裝的好處就體現出來了,因為專案中所有的地方都是使用封裝過的input框,所以只需要在封裝中做改造就好了。ios中點選虛擬鍵盤的完成按鈕會觸發失焦事件,安卓卻不會,正是我們需要的鉤子。

在鉤子中設定“推回”:

    onBlur = (e) => {
        const { onBlur } = this.props;
        document.body && (document.body.scrollTop = 0);
        onBlur && onBlur(e);
    }
複製程式碼

問題初步解決,但是引發的新問題也很明顯,任何onBlur事件都會做出 scrollTop = 0 的操作,嚴重影響體驗。

繼續通過現象思考問題,當我們使用滑動觸控事件的時候,body會“跳動”到正常位置,而不不是正常的滾動,這一點很重要!

這表明了瀏覽器做了一個錯誤的渲染,那我不禁想到,我們做的“推”的操作是否必須?在一個錯誤的渲染下,我們是否只需要在鍵盤收起後做一個觸發“重繪”的操作。

solution!

問題解決了,最終解決方案就很明顯:

    onBlur = (e) => {
        const { onBlur } = this.props;
        document.body && (document.body.scrollTop = document.body.scrollTop);
        onBlur && onBlur(e);
    }
複製程式碼

在input輸入框失去焦點的鉤子中設定滾動到原有位置(document.body.scrollTop = document.body.scrollTop),觸發瀏覽器的重繪,使的錯誤的渲染回覆正常,滾動位置也不會有改變,沒有影響體驗。

是不是很簡單?

解決方案的簡單,是建立在深層的思考中的,如果這篇文章能對你有所觸動,那我的寫作就沒有白費。

更新一下評論區出現的方法,感謝 @ibca 提供。

(絕望的是我出現bug時去搜尋這個問題竟然沒有找到可用答案??)

/**
 * 處理iOS 微信客戶端6.7.4 鍵盤收起頁面未下移bug
 */
;(/iphone|ipod|ipad/i.test(navigator.appVersion)) && document.addEventListener(`blur`, (e) => {
    // 這裡加了個型別判斷,因為a等元素也會觸發blur事件
    [`input`, `textarea`].includes(e.target.localName) && document.body.scrollIntoView(false)
}, true)
複製程式碼

— The End

相關文章