在小程序中,咱們常常有調起鍵盤的操做場景,可是在不一樣的場景下解決方案不盡相同,仍是須要具體問題具體分析。javascript
最近在項目中有一個需求,是從列表頁點擊評論按鈕進入詳情頁時,在加載完頁面後自動調起鍵盤進入評論狀態。從需求來看,咱們應該在onReady函數中調起鍵盤,由於onReady函數是在頁面初次渲染完成時被調用。可是在實踐中咱們發現,對於一些配置很差的手機,其加載頁面速度較慢,在onReady函數調用時頁面並無渲染完畢,就會致使placeholder和input組件位置錯亂的現象。其本質緣由是,onReady生命週期函數並不能在調用時承若已經將頁面渲染完成了。(儘管文檔中描述是已經完成了。)java
以前的操做是在onReady生命週期函數中調起鍵盤。react
this.setData({ focus: true })
複製代碼
發現這個問題後作了相應的延遲處理小程序
setTimeout(() => {
this.setData({ focus: true })
}, 300)
複製代碼
但這是治標不治本的方法,手機性能好的用戶會無謂的等待300毫秒,而手機性能不好的用戶等待300毫秒也不必定就能解決這個問題。微信小程序
那麼既然小程序並無提供給咱們一個理想的渲染結束後的回調函數,那麼咱們就換個思路:使用短輪詢來處理,當頁面渲染完成後才調起鍵盤的操做。微信
既然要使用短輪詢,那麼咱們去輪詢什麼呢?什麼標誌表明着頁面渲染完成了呢?在這裏,我是使用wx.createSelectorQuery()
方法,它會返回一個SelectorQuery對象實例,在這個實例上調用select方法選擇我想要去輪詢的節點,在回調函數中判斷參數是否爲null
。若是返回了監控的節點信息,那麼說明已經渲染完成。這時就能夠進行鍵盤調起操做了。函數
let timer = setInterval(() => {
wx.createSelectorQuery().select('#comment-section').boundingClientRect(rect => {
if (rect !== null && timer !== null) {
clearInterval(timer)
timer = null
this.setData({ focus: true })
}
}).exec()
}, 50)
複製代碼
在此之上,若是咱們只粗暴的讓focus
爲true
並非個明智的作法。性能
在調起鍵盤時默認頁面會上推,若是在評論不多的狀況下這樣的體驗並很差。因此須要判斷一個高度,超過這個值就上推,沒超過就不上推。這個值視實際狀況而定。 上推的操做是由input組件的adjust-position
屬性決定,爲true則上推,不然則不上推。這時回調返回的參數中的節點信息就能夠派上用場了。ui
// 在this.setData({ focus: true })前對節點高度進行判斷
if (rect.height < 500) this.setData({ push: false })
else this.setData({ push: true })
複製代碼
在實際的操做中,咱們發如今鍵盤被調起後會有概又自動收回。通過排查發現時onBlur函數的問題,在onBlur函數中,咱們手動的設置focus
爲false
,但其實並不須要這一步操做,反而帶來了反作用。在咱們去除了這部分代碼後,鍵盤自動收起的問題獲得瞭解決。this
雖然咱們完成了此次任務的需求,可是顯而易見的,這樣的任務在將來確定還會再次出現。因此機智的咱們應該趕快把整套流程封裝起來,以便下次直接調用。
那麼這時咱們使用的方式就是這樣的:
const Util = require("xxx") // 引入封裝的庫
/** * 生命週期函數--監聽頁面初次渲染完成 */
onReady: function () {
Util.onTotalReady('#comment-section', 50, rect => {
if (rect.bottom < 500) this.setData({ push: false })
else this.setData({ push: true }}
this.setData({ focus: true })
})
}
複製代碼
在解決鍵盤調起的這個過程當中咱們能夠看出微信小程序開發流程的簡陋,這個問題的出現本質上是小程序提供給咱們的生命週期函數的不夠準確。不然在頁面渲染完成的狀況下我怎麼會拿不到節點信息呢?像react中的componentWillMount生命週期函數中就不會出現這樣的問題,因此但願小程序能再變強大一些,也讓咱們少寫一點這種hack代碼。