前言:這里移動端主要指 hybrid app 中的H5頁面。app 中對頁面 樣式和功能 的需求會更精細一點。
1、適配: 手機端的尺寸多樣,3.5英寸的 iPhone4應該是最小的,只要考慮 兼容到iPhone4 就可以了。(iPhone4的用戶量現在也很少,有時只要 兼容到iPhone5 就可以了)
哪怕有比這個尺寸小的,都不是多人使用的。可能是個位數,甚至是沒有。為數不多的幾款這樣的手機處理能力也很低下。 https://digi.tech.qq.com/a/20150312/011872.htm#p=1
iPhone4 使用情況:iPhone4的系統, 現在的很多軟件都運行不了。 https://www.pc841.com/shouji/iPhone/19249.html(系統升級后也會有問題,大部分用戶是不會去升級的) 或 https://t.cj.sina.com.cn/articles/view/2972527830/b12d2cd60010084gl
總結:
rem + 媒體查詢 適配(rem基本可以適配大部分的移動端的適配,解決不了的使用媒體查詢基本可以解決),重點熟練下媒體查詢手機是用height還是device-height來查詢的。有的手機,下面有一條黑色的手機按鍵,此時的device-height有沒有包含這塊高度。
注:不同手機寬度基本沒什么適配的,rem基本就解決了。主要是針對需要一屏顯示的頁面,高度差距太大,用rem基本沒什么效果。
2、 JS 呼起和隱藏鍵盤(默認是需要用戶點擊輸入框才能呼起): 智能機的鍵盤都是軟鍵盤。應用中有呼起鍵盤和隱藏鍵盤的需求。
呼起鍵盤:進入搜索頁,要求鍵盤拉起。主要聚焦到input框就可以。(安卓上沒有問題,ios上無效)
this.$refs.input.focus() // 在一個demo上安卓 和 ios都有效,但是正式項目中,ios中無效
隱藏鍵盤:通過給input標簽,設置 readonly 屬性就可以使鍵盤收起來了。(安卓上沒有問題,ios上無效)
<input type="text" ref="input" :readonly="readonly">
或,下面的方法 安卓 和 ios上都有效
this.$refs.input.blur()
3、軟鍵盤呼起 引起的兼容性問題:
a、 會使webview高度變小(這里就要求body最好設置一個最小的高度為沒有鍵盤時的高度),並且 fixed定位元素 跟着鍵盤上移 (安卓的問題):
問題原因:
安卓手機:同一個手機,H5頁面的 視口高度在鍵盤拉起和隱藏時,不一樣的。拉起時,鍵盤部分的高度變成原生的內容了,H5容器高度就變小了。(H5頁面本身的高度是不變的)
一般情況這個都不影響,但是如果底部有fixed定位的話。鍵盤拉起時,會把這塊內容也移上去的,需要做一個判斷進行隱藏(這個隱藏必須是針對對安卓機,ios機上不能隱藏。ios上也隱藏了,鍵盤)。
ios手機:更不正常,鍵盤彈出不影響H5容器的大小變化的,即clientHeight的大小不變,但是卻出現了滾動(如果clientHeight同步變小,可以理解為變成了一個小屏的容器。但是ios這樣,只是把滾動條的范圍變小了;
滾動條到底了,頁面的底部在鍵盤的上了。鍵盤遮擋的部分也是屬於clientHeight,這一部分的高度,憑空給H5頁面了)。總結起來就,ios中鍵盤彈起,會給H5頁面的高度增加了一個鍵盤的高度。
參考哪些高度發生的變化 https://blog.csdn.net/weixin_34163553/article/details/88686238
個人看法:鍵盤彈出,可以這樣理解為h5的底板的大小就是webview的大小,包括鍵盤。底板上一張畫布,畫布高度可以被撐高,html、body等元素是固定在畫布上的。瀏覽器中頁面的滾動的跟着畫布滾動的。
安卓上,畫布的最小高度是底板不包括鍵盤的高度; ios上,畫布的最小高度是低板的高度加上鍵盤的高度。(css無非操作畫布的屬性)
解決問題:
頁面只能是一屏的:這個要考慮自適應。鍵盤呼起,webview的高度變小了。使用 absolute 定位,bottom 設置,定位參考的元素高度不能受webview高度的影響(給body設置一個最小高度,開始就通過js獲取);或者使用top設置高度。
如果,要考慮所有手機中 底部的按鈕必須離底部相同的距離。這個可能就要使用js獲取 沒有鍵盤時屏幕的高度。然后把 定位參考 元素高度設置為這個值。
頁面可以滾動:這個比較簡單,沒有鍵盤時,頁面高度已經 大於 容器的高度了。呼起鍵盤后還是滾動的。沒有任何的問題。
b、軟件盤喚起,在表單 外滑動,軟鍵盤不關閉,點擊才會關閉(這點表現,兩者是一樣的,沒有兼容性問題,記錄下這個特性)。
c、軟件盤的關閉方法,表單失去焦點 / 軟件盤上的關閉按鈕 (這點表現,兩者是一樣的,沒有兼容性問題,記錄下這個特性)
d、點擊軟鍵盤上的關閉按鈕、安卓手機不會觸發 表單的 blur 事件,ios可以。(安卓的問題)
需要 軟件盤關閉時 執行代碼,在安卓上就需要做兼容處理。(解決安卓的一些兼容性問題,必須要在軟鍵盤關閉時執行。如鍵盤拉起時,會把底部fixed元素移上去的,需要做一個判斷進行隱藏;關閉軟鍵盤時,再顯示)
e、軟鍵盤喚起時fixed 元素失效(ios的問題):如下說明
4、 軟鍵盤呼起時fixed失效(fixed+input,ios的問題):(有一個inobounce插件,可以直接解決這個問題。功能上相當於使得畫布的高度,始終等於鍵盤上面到頂部的高度。不管鍵盤有沒有出來都這樣。有時間可以看下源碼)
a、頂部 fixed元素,input框在頂部:點擊這個input框,fixed雖然失效了,但是頁面不會滾動。fiexd元素會滾動是因為軟鍵盤的彈出,fixed失效了(或變成了absolute),只要input失去焦點時,立刻把鍵盤關閉,fixed元素就沒有滾動的機會。
這樣就可以解決fixed無效的問題了。
中間部分有滾動部分的解決方案,有效 https://www.iteye.com/blog/570109268-2406086(解決了中間滾動部分的高度,不會引起畫布的滾動。畫布的滾動,還是會使fixed滾動,這個解決方法就是上面說的失去焦點,隱藏鍵盤)
b、底部 fixed元素,input框在底部:這個input輸入框,點擊這個輸入框,頁面都會向上滾動的。input框始終在鍵盤上面,鍵盤關閉,滾上去的頁面也不會滾下來。
這個 當表單失去焦點時(或觸發鍵盤隱藏事件時),讓頁面滾動到之前的位置就可以解決:
document.documentElement.scrollTop = 100; // 這個值是彈出鍵盤前的位置
inobounce 禁止IOS H5的滑動回彈 :https://blog.csdn.net/weixin_30610755/article/details/95260237
5、解決頁面,返回時重復的問題 (重要,app中返回是經常會用到的,所以瀏覽器歷史記錄需要頁面控制下。頁面前進或回退時,url只是參數的改變,頁面是不刷新的)
A(列表頁) =》 B(詳情頁,B中有跳到A頁面的按鈕):列表A1 =》 B 點擊跳到A的按鈕 =》
列表A2 =》B。這個時候回退時,B=》A=》B=>A 會出現不斷重復的問題
解決方案:使用vue路由的 vm.$router.replace() 方法跳轉,或 原生的 location.replace(URL)
6、input中占位文字,無法上下居中對齊(應該是字體小於12px,引起的問題)。
7、ios監聽軟鍵盤確認按鈕:會無效(那個 確認 按鈕會變化 為換行 按鈕,換行時,監聽key=13是對的。變成確認時,監聽不了key=13的這個鍵。【猜測可能同一個鍵,確認的鍵盤碼不是13】)
解決辦法: type="search" 的輸入控件,會使改變軟鍵盤確認按鈕的文字變成搜索(且鍵盤碼都是13)。https://blog.csdn.net/sinat_24070543/article/details/53423274
<form action=""> // form 標簽必須加 <input v-model="wordName" type="search" placeholder="輸入垃圾名稱搜一搜" @input="inputText" ref="input"/> </form>
這個方法可以不用監聽key=13事件,直接監聽form的 submit 事件同樣可以監聽 確認按鈕。
(項目中是 在 搜索框 右邊加一個 搜索按鈕,不使用軟鍵盤上的確認按鈕)
另:type=search表單,輸入文字后,右邊會有一個刪除文字按鈕的。解決方案:https://www.cnblogs.com/xiaoshen666/p/10772858.html
input[type="search"]::-webkit-search-cancel-button{ -webkit-appearance: none; }
8、小高度標簽內 單行文本 垂直居中 偏上的解決方案(安卓設備上):https://blog.csdn.net/zhanghuanhuan1/article/details/80339610 或 https://blog.csdn.net/liming911911/article/details/75389188(推薦)
原因(個人猜測):移動端是支持12px以下的字體的。安卓上小於12px的字體,字體會溢出標簽一點。親測,如下圖,設置了居中的樣式,字體設置為10px,字體溢出他的包含標簽sapn。即,
瀏覽器12px以下的字體 以12px顯示;移動端小於12px的字體,也可以正常顯示,但是排版有點小問題(會上移)。
常規的居中方案都沒有用的,使用scale可以近似解決,但是不夠完美。目前沒有其他的可行方法。或者使用媒體查詢,小於12px的尺寸,就以12px顯示。折騰了好久,找不到好的辦法
9、ios上vue框架中返回 keep-alive 的頁面(這個頁面比較長,有滾動。滾到頂部,進入下一個頁面),會出現白屏(被什么東西遮擋住了)。手輕輕滑動下,遮擋層就消失了。
原因及解決方法:https://blog.csdn.net/m0_38069630/article/details/80573283 (公司的項目中因為是多人開發,不好動html, body的屬性。所以沒用這個解決方案,只是不用 keep-alive 了)
10、ios中 h5頁面 輸入框點擊空白處不會失去焦點 軟鍵盤不會收起(重要):
解決方案:https://www.cnblogs.com/gd-dql/p/7476330.html(親測有效,里面使用touchend觸發,改成touchstart更好。有時間整理下,把里面的定時去掉)
11、ios-H5 中,不過頁面的高度是多少(html,body設置為50px,只有一個input標簽),只要鍵盤彈出,頁面就一定會滾動 。通過上面的方法,input失去焦點馬上隱藏鍵盤。這樣活動的時候鍵盤隱藏,頁面就不會滾動了。
但是,在input內部滑動,還是會帶動頁面滾動的,給input標簽添加一個touchmove阻止默認事件。就完美了
document.getElementById('input').addEventListener("touchmove",function(event){ event.preventDefault() },false)
(直接讓頁面不滾動,暫時沒有找到解決方案,因為html,body的高度根本沒有超出鍵盤的范圍。我想應該是有直接的解決辦法的,百度H5頁面,不知道是怎么解決的,有時間研究下)
12、禁止 ios 頁面上下滾動回彈(橡皮筋效果):沒有橡皮筋效果,就不會出現fixed失效的問題。
解決方案1、使用 inobounce.js 插件(親測有效)。但是 整個頁面都不能滑動了,有溢出的屏幕的元素也不能滑動的。
如果有需要滑動的元素,需要設置一個height或max-height,還有overflow: auto; -webkit-overflow-scrolling: touch; https://blog.csdn.net/weixin_30610755/article/details/95260237
解決方案2、參考 https://blog.csdn.net/m0_37068028/article/details/80183781 (親測,兩個方案都有效)
說明:通過閱讀 inobounce.js 的源碼(源碼代碼量很少),發現 原理就是使用window代理屏幕上的 touchmove 事件( window.addEventListener)。判斷當前觸發的對象是非滾動區域,則阻止事件的默認行為;滾動區域,不阻止事件。
具體實現,插件中考慮的比較全面,比較復雜。直接使用插件是最方便的。
13、js沒有監聽 手機端軟鍵盤 彈出 / 關閉事件,可以封裝一個這樣的函數。https://www.cnblogs.com/wind-wang/p/10711259.html
安卓 和 ios 對軟鍵盤關閉的行為是不一樣的。安卓中 軟鍵盤關閉,webview高度變化(blur事件不一定觸發);ios中 軟鍵盤關閉,觸發 blur事件【或focusout】(webview高度沒有變化)。
14、 fixed的遮罩層上面可以滾動,下面內容禁止滾動。 (有時間再單獨研究下,fiexd遮罩層上的事件,如點擊,滾動對下面的內容的影響)
解決方案:移動端開發,body內的元素,最外層的標簽要設置一個高度(一般是容器的高度100vh),溢出屬性設置滾動。不要讓body的高度超過100vh了,不然 fixed的遮罩層上面滾動,下面的內容一會滾動。處理起來比較麻煩。
親測問題:在fixed層上使用vue的 @touchmove.prevent 阻止默認事件,結果上下兩層的滾動都禁止了; 使用 @touchmove.stop 阻止冒泡事件,結果無效。
問題分析:
a、body 的 高度超過 容器高度,body是比較特殊的標簽。fixe層的touchmove事件,會導致body滾動。
b、非 body的標簽,如 div標簽是一個溢出滾動的標簽,其內的一個標簽作為 fixed遮罩層,則遮罩層內的內容滾動,不會觸發這個div標簽的高度。(個人猜測,遮罩層雖然在div標簽內,但是已經脫離標准文檔流,事件上於div已經沒有關系)
c、body是比較特殊的 標簽,fixed遮罩層內 的 touchmove 還是會到 body上的。
15、 IOS獲取短信驗證碼--自動填充被復制兩遍問題: 參考鏈接
說明:測試測出這個bug,自己測試一直沒復現出來。可能觸發機制不是很准確。
16、video標簽,在安卓手機 不能自動播放: https://blog.csdn.net/weixin_34037173/article/details/88718114
在安卓的容器(webview)中,視頻播放需要點擊兩次,即播放-暫停-播放,才能開始播放。(暫時沒有找到解決方案)
17、移動端 input[type=file] 標簽 本地文件、拍照、錄像 上傳的兼容性問題: 參考自己的另外一篇博客,https://www.cnblogs.com/wfblog/p/12887737.html
18、安卓中video播放完 視頻 后,會自動跳到,視屏廣告的內容上去。https://blog.csdn.net/Dream_Weave/article/details/103095517
總結:安卓和ios的兼容性,主要的問題,還是軟件鍵盤引起的。所以兩者關於軟鍵盤的處理一定要讓他們盡可能的保持一致。如下要做到一致:
a、輸入框,聚焦時彈出軟件盤。失去焦點時,隱藏軟件盤(ios需要處理的)。
b、ios 的 橡皮筋效果 一定要禁掉(使用 inobounce 插件)。
c、ios 和 安卓 兩者 對軟鍵盤關閉 的判斷的邏輯不同(軟鍵盤關閉時,執行代碼這個功能是一定會用到的)。現在的手機 不是ios就是安卓手機,可以把這兩段代碼封裝在一個方法里,變成一個軟鍵盤關閉的事件(實際開發中,一般只是對一種情況做出處理)。
if(isIOS){ // 在 ios 中執行下面監聽事件,捕獲 軟鍵盤關閉事件。(isIOS 通過獲取 navigator.userAgent就可以判斷) window.addEventListener('focusin', () => { // 鍵盤彈出事件處理 alert("iphone 鍵盤彈出事件處理") }); window.addEventListener('focusout', () => { // 鍵盤收起事件處理 alert("iphone 鍵盤收起事件處理") }); }
if(isAndroid){ // 在 android 中執行下面監聽事件,捕獲 軟鍵盤關閉事件 const innerHeight = window.innerHeight; window.addEventListener('resize', () => { const newInnerHeight = window.innerHeight; if (innerHeight > newInnerHeight) { // 鍵盤彈出事件處理 alert("android 鍵盤彈窗事件"); } else { // 鍵盤收起事件處理 alert("android 鍵盤收起事件處理") } }); }
感悟:1、如果不用 輸入框,基本沒有什么兼容性問題。css的兼容性問題也基本沒有,就幾個默認樣式的區別;沒有軟鍵盤,ios回彈效果也沒什么影響,可以不做處理。
2、上面講的安卓和ios上的兼容性問題,都是webview內核的兼容性問題。hybrid-app中SDK方法也會有兼容問題的,這種bug完全就是安卓和ios軟件開發者沒有(或無法)統一引起的。一般安卓和ios是不同的人開發的。
同樣的微信軟件,在ios上和安卓上清除緩存的功能都是不一樣的。微信JS-SDK,在處理分享鏈接鏈接也是有差異。自己公司開發是“杭州辦事服務”APP,JS調用原生的語音功能也存在兼容性問題。
文章閱讀
1、移動端項目實戰心得: 參考鏈接
移動端事件: https://www.jianshu.com/p/201518903985(原生的沒有 tap 和 swipe 事件)
1、touch事件:
touchstart:手指觸摸到屏幕會觸發
touchmove:當手指在屏幕上移動時,會觸發
touchend:當手指離開屏幕時,會觸發。
touchcancel:可由系統進行的觸發,比如手指觸摸屏幕的時候,突然alert了一下,或者系統中其他打斷了touch的行為,則可以觸發該事件。(在瀏覽器的模擬器中觸發touchcancel事件,Alt+Tab鍵)
注意:使用 touchend 事件時,一定要考慮touchcancel事件。比如,語音功能。按下說話,突然彈出 語音權限未開。這個時候手指拿開就不會觸發touchend事件了,touch事件被打斷了,屏幕上一直是touchstart的狀態。
必須加上 touchcancel 事件,補充 手指拿開后的頁面狀態。
移動端各種高度:(在pc上,瀏覽的高度對用戶基本什么問題。但是在移動端瀏覽的各種高度問題。比如webview的高度,是否包含軟鍵盤,不同的系統有差異性。微信的H5頁面,底部有左右前進按鈕欄,webview的高度是否又包含這個)
參考:https://segmentfault.com/a/1190000010443608 或 https://www.jianshu.com/p/27b68f780054?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
1、window.outerHeight:【不常用】窗口的外部高度,包括所有界面元素(如工具欄/滾動條)。手機端,這個值和innerHeight一樣。
2、window.innerHeight:【一般】瀏覽器窗口高度(包括橫向滾動條的高度,沒有橫向滾動條,和documentElement.clientHeight是一樣的。https://www.cnblogs.com/suihang/p/11177093.html )。(ios中軟鍵盤彈出時,有兩個值)
3、body.offsetHeight:【不用】網頁可見區域高(不確定具體的含義,值和scrollHeight一樣。)。
4、body.clientHeight(兼容問題):瀏覽器窗口高度(不包括橫向滾動條)。(不同瀏覽器表達方式不一樣,谷歌中他的值無效。使用 documentElement.clientHeight【常用】)
5、body.scrollHeight(兼容問題):網頁正文 全文高。可以理解為畫布的高度。(谷歌中他的值表示body的高度,使用 documentElement.scrollHeight【常用】。https://www.cnblogs.com/nanshanlaoyao/p/5964730.html)
6、body.scrollTop(兼容問題):滾動條在Y軸上的滾動距離,即文檔上邊出去的高度。(谷歌、火狐上都為0,使用 documentElement.scrollTop【常用】 。https://www.jianshu.com/p/4c37a2a56586
)
兼容性解決方案:https://www.cnblogs.com/winyh/p/6715010.html
7、window.screenTop:【不常用】窗口相對於屏幕的Y坐標。即瀏覽器頂部距離顯示器頂部的距離。https://www.w3cschool.cn/jsref/prop-win-screenleft.html
8、screen.height:【不常用】屏幕分辨率的高,即顯示器的高度。
9、screen.availHeight:【不常用】顯示器除去底部任務欄后的高度。https://www.w3school.com.cn/jsref/prop_screen_availheight.asp
各種高度 | 鍵盤沒有彈出(安卓) | 鍵盤彈出后(安卓) | 鍵盤沒有彈出(ios) | 鍵盤彈出后(ios) | 微信網頁底部左右箭頭欄隱藏(ios) | 微信網頁底部左右箭頭欄顯示(ios) | ||
window.outerHeight | 647 | 380 | 603 | 603 | ||||
window.innerHeight | 647 | 380 | 603 | 603,293(滾動到底部) | ||||
body.offsetHeight | 771 | 771 | 793 | 793 | ||||
body.clientHeight | 771 | 771 | 793 | 793 | ||||
body.scrollHeight | 795 | 795 | 817 | 817 | ||||
body.scrollTop | 0 | 68 | 0 | 0 | ||||
window.screenTop | 0 | 0 | 0 | 0 | ||||
screen.height | 720 | 720 | 667 | 667 | ||||
screen.availHeight | 720 | 720 | 667 | 667 |