前言
记录Hybrid App 内嵌 H5开发中常遇到的一些bug
Hybrid App,Hybrid(混合),就是原生App里打开webApp,相当于native提供了浏览器内核打开web页面,当web页面交互比较多会有很多兼容问题。
感觉很多bug在一般手机浏览器里都是不存在的,但在App里打开就有了,最开始是在微信浏览器里出现bug。后面从笔者开发 App内嵌H5页时就遇到了一些bug,简单记下
1. iphone上的input fixed定位
-
在iphone上,按钮点击弹出一个文本框,用户可以在文本框输入,为了有更好的体验,在点击按钮的时候会给文本框添加一个获取焦点事件,这样点击完按钮就直接输入而不必再点一下文本框输入,若页面上有定位就容易失效,如果是
position:fixed
,focus
时fixed
会失效,以致页面排版出现问题,用户体验不好。解决方法: 尽量别用定位,非得用就用absolute
2. rem布局的一些问题
-
1.rem布局,可能会在三星note4、红米等手机上出现页面排版混乱的问题,rem还是慎用,移动端布局可以用flex
解决方法:非得用rem的话就只能一点点调整根元素大小,也可用 navigator.userAgent 获取手机型号,单独给不兼容的手机提供一个 font-size。
-
2.项目里的border用rem单位,在有些安卓手机上是会显示不出来。
解决方法:直接用 px
3.line-height属性在在安卓手机表现有问题
-
一行文本想垂直居中,最简单的办法就是把 line-height 设置为文本所在标签的高度,但是在安卓手机上会有问题。
解决方法: 安卓手机单独设置 line-height。比如本来标准的 line-height 是0.5rem,但是在安卓上设了0.35rem, 或者给一点 padding-top,网上有很多解决办法,但是都不怎么靠谱。也不知道具体兼容性,可以特殊处理
4. iphone 文本框输入完点回车操作会有一个问题
-
1、键盘上的搜索键
可能显示的不是‘搜索’这两个字,显示的就是‘下一项‘,有的显示的是‘换行’,这样体验也不是很好,有些人肯定输入完以后没看到搜索按钮会懵逼,所以把键盘的enter键的字改成搜索是有必要的
解决方法:input框用form标签包起来即可
-
2、移动端做搜索的时候用到keyup或者keydown事件在iOS上的兼容问题
iOS自带的键盘有一部分是不触发键盘事件的,如输入了shi,键盘上方会有一排待选的字,点击选择字,这部分是不触发键盘事件的,所以说如果我选了个“是”字,是不会触发搜索的,这算个bug吧,第三方输入法上不会存在,但iOS用自带键盘的用户也很多,所以还是得解决
解决办法: 就是将键盘事件换
input propertychange
事件就可以; 例:把$('.search').keyup(function(){})
换成$('.search').on('input propertychange',function(){}),
是js原生的方法,就是oninput,类似于onclick,可以实时监听文本框的内容。 (该bug在手机浏览器和App里均会出现)。
5. 移动端如果要用css3动画
必须要加前缀,-webkit-,否则在安卓手机上动画会失效,iOS是没问题。
6. 移动端 click 事件300毫秒的延迟 与 click 穿透
-
1.为什么会产生延迟
iOS 中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 click 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App 中,无论是否需要双击缩放这种行为,click 单击都会产生 300ms 延迟。
最好用touch事件,别用click,非用click,且是在手机浏览器里打开的话click事件也能正常执行,看不出来延迟效果,至少我没看出来,可以直接用click。 但是如果要在App里打开的话,click事件的延迟十分明显
解决方法: 1、把click事件全部改为touch事件 2、利用fastclick插件,可以清除click事件的300毫秒延迟,但fastclick好像不小
-
2.为什么会click穿透
双层元素叠加时,在上层元素上绑定 touch 事件,下层元素绑定 click 事件。由于 click 发生在 touch 之后,点击上层元素,元素消失,下层元素会触发 click 事件,由此产生了点击穿透的效果。
解决方法:1、与上一个问题类似,使用 touchstart 替换 click, 将 click 替换成 touchstart 不仅解决了 click 事件都延时问题,还解决了穿透问题。 因为穿透问题是在 touch 和 click 混用时产生。
一般的触摸滑动事件的触发过程 是
touchstart - touchmove - touchend - click
7. ios滑动卡顿问题
在ios浏览器中上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。
解决方法:
1.在滚动容器上增加滚动 touch 方法
将-webkit-overflow-scrolling 值设置为 touch
body { -webkit-overflow-scrolling: touch;}
设置滚动条隐藏:body ::-webkit-scrollbar {display: none;}
2.设置 overflow
设置外部 overflow 为 hidden,设置内容元素 overflow 为 auto。内部元素超出 body 即产生滚动,超出部分 body 隐藏。
body { overflow-y: hidden;} .wrapper { overflow-y: auto;}复制代码
8. 页面放大或缩小不确定性行为
双击或者双指张开手指页面元素,页面会放大或缩小。
HTML 本身会产生放大或缩小的行为,比如在 PC 浏览器上,可以自由控制页面的放大缩小。但是在移动端,我们是不需要这个行为的。所以,我们需要禁止该不确定性行为,来提升用户体验。
HTML meta 元标签标准中有个 中 viewport 属性,用来控制页面的缩放,一般用于移动端。
解决方法:
head标签里 设置 meta
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
9. iPhone X系列刘海屏安全区域适配问题
头部刘海两侧区域或者底部功能条区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域
解决方法:
设置安全区域,填充危险区域,危险区域不做操作和内容展示。
head 标签中 meta标签 viewport-fit 设置为 cover,获取所有区域填充。 判断设备是否属于 iPhone X,给头部底部增加适配层
// 设置 viewport-fit 为 cover
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
// 使用 safe area inset 变量
/* 适配 iPhone X 顶部填充*/
@supports (top: constant(safe-area-inset-top)) or
(bottom: constant(safe-area-inset-bottom)){
body, .header {
padding-top: constant(safe-area-inset-top, 40px);
}
body, .footer{
padding-bottom: constant(safe-area-inset-bottom, 20px);
}
}
/* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */
@supports (bottom: env(safe-area-inset-top)) or
(bottom: env(safe-area-inset-bottom)) {
body, .header {
padding-top: env(safe-area-inset-top, 40px);
padding-top: var(safe-area-inset-top, 40px); // env 不生效时触发
}
body, .footer{
padding-bottom: env(safe-area-inset-bottom, 20px);
}
}
10. 微信公众号分享问题
在微信公众号 H5 开发中,页面内部点击分享按钮调用 SDK,方法不生效。
解决方法:添加一层蒙层,做分享引导即可。
11. H5 调试相关方案策略
- 使用 vsconsole
// 导入
npm install --save-dev vsconsole
// 使用
import Vconsole from 'vconsole'
new Vconsole()
- chrome://inspect/#devices chrome 浏览器直接使用,手机端要开启USB调试功能,访问页面就能直接看到,可以直接使用chrome的扩张调试一些手机的功能
12. Android 与 H5交互数据的一些注意点
- 对 Android 传的
\
的处理Android
和前端交互只能传字符串,iOS
可以传对象类型,所以遇到对象类型只能让安卓转成JSON字符串前端再解析,但是遇到反斜杠\
,就会出错,JSON.parse 解析时直接报错
这是 Android
传过来的字符串就有问题,当出现\
时,由于 JavaScript
中它是个转义符,所以JSON.parse
的时候\\
会被解析成\
,一个反斜杠就直接报错
安卓返回的反斜杠都缺了一半那就手动给它补上一半,直接匹配安卓传给前端的字符串用String.prototype.replaceAll()
去转换,JSON.parse
解析后,在替换回来就行
var data = '{"a":"\\"}'
var data2 = data.replaceAll('\\','\\\\')
JSON.parse(data2) // 正常解析出 {a: '\\'}
- H5 传给 Android 数据有
+
号的注意点 需要先在前端将+
转成%2B
,Android
解析才不会出错
这通常出现在需要给Android
传递base64时需要用到,因为base64编码有+
号,同样使用String.prototype.replaceAll()
去做转换
var data = {"a":"base64+324qwe+ABKGF"}
data.a = data.a.replaceAll('+', '%2B')
data3 = JSON.stringify(data) // '{"a":"base64%2B324qwe%2BABKGF"}' 传递给 Android
13. Native 中 H5 video 播放问题
Android
非全屏和全屏模式使用的都是 h5的播放器。h5的播放器在安卓的webview内是有一些问题的。
-
进入全屏后,看一段时间后自动锁屏(应该是h5 的播放器没有触发系统的常亮功能)
解决:客户端定义一个方法,H5端在点击全屏的时候,通知客户端,不要熄屏;
退出全屏的时候,再告诉客户端,可以恢复正常的熄屏功能。 -
进入全屏后,再退出全屏,页面自动回到顶部,这个也是贼拉奇怪
解决:在点击全屏时,mark 一下当前屏幕的滚动高度。
退出全屏时,再设置当前页面滚动到指定位置,用户并感知不到主动设置页面滚动到指定位置,异常丝滑
function enableFullScreen (videoeData) {
// 点击全屏按钮时,记录当前页面的滚动位置
this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop
// 安卓进入全屏播放,需要告诉客户端不熄屏
if (dsbridge.hasNativeMethod('common.isKeepScreenOn')) {
dsbridge.call('common.isKeepScreenOn', 'true')
}
},
cancelFullScreen () {
// 安卓退出全屏后,关闭屏幕常亮模式
if (dsbridge.hasNativeMethod('common.isKeepScreenOn')) {
dsbridge.call('common.isKeepScreenOn', 'false')
}
// 由于安卓退出全屏后,默认情况下页面会自动回到顶部,这里需要处理一下
if (utils.isInAndroidApp()) {
document.documentElement.scrollTop = this.scrollTop
document.body.scrollTop = this.scrollTop
}
}
最后
以上的方式总结只是自己学习总结,有其他方式欢迎各位大佬评论
渣渣一个,欢迎各路大神多多指正,不求赞,只求监督指正( ̄. ̄)
有关该文章经常被面试问到的可以帮忙留下言,小弟也能补充完善完善一起交流学习,感谢各位大佬(~ ̄▽ ̄)~