移动端(安卓、ios、微信端)的 兼容性问题

前言:这里移动端主要指 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 (亲测,两个方案都有效) 或  https://blog.csdn.net/qq_40717869/article/details/81749970(和前面的一样,只是第二种方案 说的更详细)

      里面的方案1:【纯 css 实现】
<template>
  <div class="container">
    <div>
      <p v-for="item in 200" :key="item">测试测试测试测试测试测试</p>
    </div>
  </div>
</template>
<style scoped>
.container {
  position: fixed;
  top: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  overflow: scroll;
}
</style>

       里面的方案2:【使用js,阻止 body 默认的 touchmove事件,会导致整个页面的 的上下滑动被禁止。还要 解决 里面内容 的上下滑动问题】

              目前 测试这个方案 还没有 成功,后续 会继续 验证。

  说明:通过阅读 inobounce.js 的源码(源码代码量很少),发现 原理就是使用window代理屏幕上的 touchmove 事件( window.addEventListener)。判断当前触发的对象是非滚动区域,则阻止事件的默认行为;滚动区域,不阻止事件。

      具体实现,插件中考虑的比较全面,比较复杂。直接使用插件是最方便的。

  解决方案3【完美,但是 局限 于自己的app】:ios 原生 的 app 是可以禁用 webview 的 回弹效果的。但是,在 第三方的app 中运行 ,如微信中运行H5。我们是无法让原生app 禁用 橡皮筋效果。只能从 H5 本身 考虑解决方案。

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

19、移动端1像素 边框问题【1px问题】:https://www.jianshu.com/p/fa670b737a29

  注意:1、移动端1像素 问题,和视口大小没有关系。css中的像素是逻辑像素。

     2、最后展示到屏幕上的是  物理像素 实现的,即 逻辑像素  经过计算,转化为 物理像素显示。

     3、0.5px是有兼容性问题的,安卓手机 会把  0.5px  处理成 1px,显示还是比较粗的。

   最佳解决方案:transform: scale(0.5) 

   

总结:安卓和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 68         
window.screenTop        
screen.height 720  720    667  667       
screen.availHeight 720  720    667  667       


 

原文地址:https://www.cnblogs.com/wfblog/p/11403460.html