最近一個項目掉進了移動端的大坑,包括ios下fixed佈局,h5喚起鍵盤等問題,做爲一個B端程序員,弱項就是瀏覽器的兼容性和移動端的適配(畢竟咱們能夠要求使用chrome),還好此次讓我學習了一下相關知識。讓咱們一塊兒來看一下我怎麼掙扎出這個大坑的。css
先看一下要作什麼,也就是一個文章評論的版塊,下面依次有輸入框,點贊,收藏等 。大概長下面這個樣子: react
要求也很常規,吸底,輸入評論提交。那麼上來就輸代碼吧。android
關於這種吸底操做,上來就直接選用fixed了,這種場景舍他其誰。初步的佈局就是這個樣子了。(由於我是用的react,jsx的寫法粘貼上來簡直讓人崩潰,就隨手寫一段代碼表明下,勿怪)ios
1 <body> 2 <div class='top'></div> 3 <div class='main'></div> 4 <div class="fix-bottom"></div> 5 </body>
而後css就很少寫了,瀏覽器上一看還挺想那麼回事。而後在ios上就出現了點意外狀況。就成了這個樣子(但願沒有我廠的工友)程序員
就這樣被頂起來了。。。。出現問題就算當時要快速解決沒有時間去深究,那麼下來也要去搞清楚因果,畢竟咱們不是爲了解決問題而解決問題。一塊兒看下緣由web
2.1 ios下fixed失效的緣由ajax
軟鍵盤喚起後,頁面的 fixed 元素將失效(ios認爲用戶更但願的是元素隨着滾動而移動,也就是變成了 absolute 定位),既然變成了absolute,因此當頁面超過一屏且滾動時,失效的 fixed 元素就會跟隨滾動了。chrome
不只限於 type=text
的輸入框,凡是軟鍵盤(好比時間日期選擇、select 選擇等等)被喚起,都會遇到一樣地問題。瀏覽器
2.2 如何解決app
既然ios就是這個樣子,咱們只能選擇接受現狀,只能想辦法繞過去了。大體說來兩個方向:
一、既然會變成absolute,索性直接使用absolute算了,
bottom直接以body做爲父元素來進行絕對定位,不過這種網上都不推薦,想來有更多的問題等待修正,前人的經驗仍是要借鑑的,因此我也沒有去嘗試,有興趣的同窗能夠嘗試一下。
二、不讓頁面滾動,而是讓主體部分本身滾動
若是fixed的失效,可是頁面並無超過一屏的長度,那麼不管absolut或者fixed也沒什麼差異。順着這個思路咱們回顧一下上面的結構,徹底可讓main直接滾着玩就好了。將吸底的元素和主題做爲兩大容器,主體部分,設置絕對定位,固定在屏幕中間,超出部分就自行滾動,吸底元素就能夠本身玩了
大概就是下面這個樣子:
1 <body> 2 <div class='warper'> 3 <div class='top'></div> 4 <div class='main'></div> 5 <div> 6 <div class="fix-bottom"></div> 7 </body>
對應樣式以下:
1 .cont-warper{ 2 position: absolute; 3 width: 100%; 4 left: 0; 5 right: 0; 6 top: 0; 7 bottom: 0; 8 overflow-y: scroll; 9 -webkit-overflow-scrolling: touch;/* 解決ios滑動不流暢問題 */ 10 } 11 .fix-bottom{ 12 position:fixed; 13 bottom:0; 14 width: 100%; 15 }
這樣就能避免上面那個問題了。可是ios下,對於吸底元素而言在屏幕下半部分喚起鍵盤的時候,會被遮住部分東西,有的資料提到是第三方輸入法的toolbar,我看到的現象是吸底元素被遮住了,對於這種狀況,咱們只好加個監聽事件,當喚起鍵盤的時候,設置scrollTop值,也就是說你不上來,我強迫你上來:
/** * 喚起鍵盤,滾動 */ scrollContent() { this.interval = setInterval(() => { this.scrollToEnd(); }, 500) } scrollToEnd() { document.body.scrollTop = document.body.scrollHeight; } clearSrcoll() { clearInterval(this.interval); }
設置延時切換,input當失去焦點的時候清除。
解決了佈局問題,下面就開始happy的寫功能吧,開始以前,讓咱們回頭繼續看下上面的視覺圖,是否是感受少了點什麼。咱們的提交button呢?通常來講是這樣:
這讓我如何下手,還好請教了下老大,做爲一個老司機他輕輕的告訴我三個字:網上搜。。。。。
不扯淡了言歸正傳,對於這種顯然是要利用軟鍵盤上的回車來提交信息的。你最多見的必定是搜索按鈕,就是type=‘search’的使用。若是想經過鍵盤來提交信息,就要把form表單拉出來用用了。
3.1 鍵盤提交事件
通常來講是這樣作的,將input包括在form表單內,這樣就能夠監聽submit事件了。若是有人問我是走的ajax不是form表單的話,請記得有個onSubmit事件能夠來作一些你想作的事情。代碼以下:
1 <form onClick={::this.changeInput} onSubmit={this.comment.bind(this, postID)}> 2 <Input type="text" placeholder="請輸入" id='commentInput' value={::this.getVal()} onFocus={::this.scrollContent} onBlur={::this.clearSrcoll}/> 3 </form>
可能看起來比較蛋疼,沒辦法react的jsx就是這麼蛋疼。上面的那麼多事件還真的都有必要。思路以下:
一、submit事件能夠監聽到用戶軟鍵盤的回車鍵,對於ajax提交,這裏須要咱們阻止下form的默認事件,避免form提交的刷新頁面的行爲
1 comment(postID, e) { 2 e.preventDefault() 3 // 阻止屢次提交 4 // 你的代碼 5 6 }
這樣,監聽軟鍵盤的提交事件就完成了,可是其餘問題又來了
3.2 其餘區域喚起軟鍵盤
再看一眼視覺圖,不只僅是點擊input能夠提交評論,還有一種回覆別人評論的需求,點擊回覆的label也須要喚起鍵盤來進行操做。
移動端而言對於h5的input,focus和blur能夠喚起和收起鍵盤,這樣瓜熟蒂落的咱們可能這樣作。給每一個回覆綁定個事件,點擊的時候讓input獲取焦點便可,代碼以下
1 <div className="comment-resquetion" onClick={this.changeParent.bind(this, comment.comment)}> 2 回覆 3 </div> 4 //input獲取焦點,並現實被回覆人暱稱 5 changeparentComment(val) { 6 let commentInput = document.querySelector('#commentInput') 7 commentInput.focus() 8 this.setState({ 9 parentComment: val 10 }) 11 }
這樣在android下面是能夠的,在ios下面又遇到了問題,非input觸發的事件是不能喚起鍵盤的,這樣和window.open的限制差很少,只有用戶主動的操做纔會容許喚起鍵盤,因此這樣是不能夠的。
針對這種狀況,咱們能夠投機取巧一下,既然必需要是input觸發的操做,那麼回覆那裏我直接用一個透明的input置於上方不就能夠了。
1 <div className="comment-resquetion" onClick={this.changeParent.bind(this, comment.comment)}>回覆<input type='text' className='hide-input'/></div>
css樣式以下:
.comment-resquetion{ position: relative; font-size: 0.28rem; color: #3E93C2; letter-spacing: -1px; line-height: 0.45rem; padding: 0.05rem 0 0.15rem 0.32rem; } .hide-input{ position: absolute; width: 100%; height: 0.28rem; opacity: 0; z-index: 1000; left: 0.32rem; top: 0; }
當點擊回覆的時候,其實點擊的是input,這樣就能避開限制喚起軟鍵盤了。
3.3 關閉鍵盤
到這裏,覺得就這樣結束了,結果發現還有個問題,當點擊軟鍵盤提交完成的時候,鍵盤並不能隱藏,這讓人有點尷尬,由於點擊提交按鈕以後,沒有主動收起鍵盤。由於當在軟鍵盤上操做是,io用戶的輸入行爲還在繼續,因此不會收起鍵盤,若是是點擊旁邊的button提交,就會自動收起了。既然不能主動收起,只能咱們手動強制了,在提交事件返回後,能夠手動將焦點移除,這裏最好作個延時,否則體驗有點太快。
1 this.commentInput = document.querySelector('#commentInput') 2 setTimeout(() => { 3 this.commentInput.blur() 4 // 評論成功都置空 5 this.props.changeParent(null) 6 }, 500)
到這裏這個看起來很小的功能終於結束了,有必要作個總結以供本身及有須要的同窗作個參考。
參考文章: