引言
这是笔者在过去开发H5应用时遇到的一系列兼容性问题,很多解决方式的原理并未阐述,只提供了解决问题的思路和技巧。希望帮助那些从事H5开发的同学减少解决兼容性问题的耗时。
1、ios禁用弹性滚动
问题描述
页面在没有设置滚动条或处于极限位置时,页面还是能跟随手指上下滑动。试想,如果我们开发的组件需要监听touch事件,例如:签名组件,那么弹簧效果会降低签名的体验。所以我们需要 根据具体的业务场景来禁用和启用弹簧效果
。
解决
使用inobounce ,根据业务场景手动打开和关闭弹簧效果。
iNoBounce.enable(); //开启
iNoBounce.disable(); //关闭
iNoBounce.isEnabled(); //是否可用
总共就3个api,还是比较简单的。
2、ios适配虚拟home键
问题描述
还是这张图:
如图所示,屏幕的下方有一个 黑色的横杠
(虚拟home键)。如果页面有底部菜单,这极其影响使用和美观。百度上可以搜索到一些解决方式,但是最简单最方便的方案才是我的首选。下列方案兼容性、难易程度尚可,推荐使用。
解决
设置html头部
<meta content="viewport-fit=cover" />
css中使用如下系统变量
为了兼容,需要同时使用 env
和 constant
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
3、ios纠正图片orientation
问题描述
之前曾开发过水印图片的功能,当时我们使用 canvas
来实现此功能:先将图片用cavas绘制;然后用canvas画出水印文字;最后再生成图片 (网上很多教程,这里不详细讲解了)。
但是,当使用ihpone 8及以上的机型上的企业微信app或者微信app(其他app可能会发生同样的问题,不是绝对的)进行拍照水印处理时,发现图片发生了旋转,其他机型正常。
为什么没有用jsapi去上传图片?因为很多第三方app,jsapi的上传图片功能会先将图片保存在第三方的文件服务当中,但是我们不希望发生这样的情况,我们希望把图片存在自己的文件服务当中,所以放弃jsapi上传图片。
解决
既然是机型的问题,那就针对机型做特殊处理好了:
- iphone8及以上
旋转图片
- iphone8以下
不做任何处理
获取机型要使用jsapi来获取
,通过其他的“偏方”获取一点都不靠谱。
4、ios兼容popstate合并触发
问题描述
我们先来说下应用的实现,再来谈具体的问题,这样更容易理解一些。
下面是h5单页面应用模拟openWebview的图解。
- 通过slide组件打开目标页面(其实是个组件,因为模拟的是openWebview,我们不妨称它为页面),同时为了记录历史,我们还需要调用
history.pushState
来生成一个假hash
(只修改了hash部分,pathname没有修改) - 目标页面想要关闭当前页面时,会调用某个api执行
history.back()
,这样我们可以关闭当前页面(即当前slide组件)
具体的实现就是上述的情况,我们再来说说问题:
- android: history.back()
连续执行n次
,会触发n次
popstate - ios: history.back() 连续
执行n次
,只触发1次
popstate
额~ 好吧~ 兼容!
解决
思路:记录 执行 history.back() 的总次数
,仅在最后一次需要执行时通过 history.go()
跳跃式回退。这里需要用到事件防抖。
代码如下:
// 省略具体的实现
let hideSlides = []
Slide.prototype.hide = function () {
this.comp.hide();//目标页面立即隐藏掉。后面的路由逻辑不管它。
hideSlides.push(this);
lazyHide();
}
lazyHide = debounce(() => {
let hideIndex = hideSlides.length;
if (!hideIndex) return;
//执行到这一步,可以确定的是,需要移除那些slide了
if (hideIndex === 1) {
history.back();
} else {
history.go(-hideIndex);
}
}, 50)
5、android避免软键盘遮挡光标
问题描述
安卓上,input输入框在获取焦点时会被唤起的软键盘遮盖。
我点的是手机1
下方的一个字段,很明显,已经被软键盘遮挡,导致用户无法看到输入框。
解决
使用 scrollIntoView
方法
dom.onfocus = function() {
if (isAndroid) {
setTimeout(function(){
dom.scrollIntoView && dom.scrollIntoView(false);
}, 1000)
}
}
6、ios下iframe的各种问题
todo
7、移动端点击穿透和点击延迟
todo
有错误的地方,希望大家能够谅解和指正。
Peace And Love。