Mobile开发经验沉淀
herbertliu opened this issue · 28 comments
在手Q开发过程中,遇到各种问题,解决之后沉淀如下,细分为:
1、经验沉淀:开发过程怎么快速开发并在开发过程中可以兼顾到一些场景的出现
2、疑难问题:一些机型出现的疑难问题,如和解决,以及对应的机型等问题详细描述(截图)
组织形式可以用问答的方式吧。 一个帖子逻辑扩展性比较差。
@webryan 先在这里沉淀,多个帖子不太好找,可以在这里讨论,知识的整理在基于这里的沉淀。看讨论过程也是一中享受。而且这里有个好处可以看到历史的脚印。
IOS7白屏Bug
产生原因:IOS7中,如果html header 返回了cache-control:max-age=0(或者no-cache),这个时候Browser不会cache页面,但浏览器每次请求都会携带请求头(If-Modified-Since或者If-None-Match)。如果此时服务器刚好没有修改的话,会识别成304给Browser,此时前面已提到过Browser没有缓存页面内容,导致取不到页面而白屏。详细Bug描述猛戳这里。
解决办法
-
**设置cache时间(诸如:cache-control:max-age=600):** 对于首页更新要求来讲,如果有cache的话,不利于首页及时更新,对于更新场景不多的情况,可以采取这个办法
-
**去掉cache-control字段头(我们采取这个方案)**
-
**服务器动态处理:** 当然对于以上的方案都是基于IOS7,服务器根据请求的Header头中的User-agent来单独针对IOS7及以上处理
@herbertliu 这块我感觉另开一个repository,用rm的形式沉淀性会更好,大家也更好修改和提交。
比如:
移动Web前端知识库
iOS与Android平台上问题列表
@litten 他这个已经是总结的了,总结的是基于这个讨论梳理出来的。现有讨论沉淀,然后才有梳理。我们到时候梳理会形成知识图(形成repository)。主要是有些需要讨论的,可以在这里进行一个讨论。
md的确更适合展示,先沉淀到这里吧。后面会整理一下的。 发现at没了yuanyan,战斗力差了好多
Android2.3下transform失效
Android 2.3某些页面的transform失效, 导致rotate等属性无效, 可以通过user-scale=yes部分解决.
腾讯播放器使用时遇到的坑
- iOS下单页面里初始化多个video, 会出现神奇的bug. 因此不要初始化多个video
- 使用播放器+poster覆盖掉原来的图片(例如课程详情页), 会有一段时间的白屏. 解决方法是oninit并且延时100ms才把播放器展示出来.
[经验沉淀]多页面更新
在移动端比较偏向于新开页面来处理一些事情,另外移动端的操作环境只有返回上一层和home两个操作,因此用户会经常回退到之前的页面,所以往往需要旧页面可以自动更新数据,而产品一般不会提到这些细节,所以需要开发自己保持这种习惯,不然会有很多这个bug和工作量留到测试阶段。目前有两种解决方案:
- 高版本手Q(5.0)支持WebView的广播事件,可以通过这个进行数据更新,在手Q项目中,对于可以容忍低版本更新问题的可以采用这个方案
- 利用localstorage进行页面之间的同步
[经验沉淀]tap点透问题
产生条件
如果绑定tap方法的dom元素在tap方法触发后会被干掉(隐藏,移走,删掉),则它底下同一位置的dom元素会触发click事件、或者有浏览器认为可以被点击有交互反应的dom元素(例如input的focus事件),这个称为“点透”现象。
产生原因
- click事件在移动端会有延迟(因为需要检测双击事件,移动端click300毫秒延迟的原因)
- zepto的tap事件是绑定在document.body上的,tap事件执行(冒泡之后)之前,click事件已经被"执行",只是被延迟了而已,所以在tap事件用preventDefault也无济于事
解决方案
- 底下的元素也使用tap事件,即上下两个元素使用同一种事件(tap/click)
- 不要使用tap事件,使用touchend事件处理,并preventDefault掉(不优雅,而且暴力)
- 使用fastclick库,其实现原理就是把click的300ms延迟干掉
[机型兼容][IOS]position:fixed + input问题
当input获得焦点并弹出虚拟键盘时,页面上position:fixed的元素的位置会错乱。
解决方案
- 用position:absolute模拟,这个效果不佳,在pc端hack ie6...只能呵呵
- 当input元素focus时,改成position:absolute,blur的时候再改回来
- 使用iscroll库
- 使用div内滚动
[机型兼容][IOS8]闪屏问题
大面积的页面内刷新时出现,这种闪屏不是位置错乱的那种闪屏,具体原因不详
规避方案
- 提高刷新效率,尽量减少reflow和repaint
- 刷新之后不要改变页面的scroll状态,即不要从不能scroll刷到可以scroll,反之亦然(利用min-height让页面一直处于scroll状态,在用)
- 不要刷新图片,利用localstorage缓存图片链接,命中的图片直接使用src,而不要用lazyload(在用)
[经验沉淀]别忘了点击态
就像pc端的3态,在移动端需要点击态,移动端的点击态实现是点击时添加一个active类,300ms后去掉,建议把点击态放到移动端视觉检查项中
[经验沉淀]页面的各种状态
这些状态pc端也会用到,不过在移动端会更为需要,因为移动端网络延迟高并且不稳定。建议是把页面的各种状态抽象为组件,并整合在一个组件中统一管理会比较好,这个待优化,现总结页面中会出现的各种状态:
- 加载js前,需要在html内显示【正在加载】或其它类似标志
- 加载js后,调用cgi时,显示loading标志
- 如果cgi做了localstorage缓存,在展示local数据同时拉cgi时,显示更新数据标志
- 数据为空时,应该展示空标志(不管是cgi返回空结果,还是页面更新数据后变成空结果)
- cgi加载失败,显示重试提示,点击后可触发重试逻辑
[经验沉淀]cgi添加localstorage逻辑之后需要注意的地方
- 变量重复初始化
- 事件重复绑定
- 页面状态切换
[机型兼容][IOS 5+]快速回弹滚动问题
IOS5新特性webkit-overflow-scrolling: touch可以启动快速回弹滚动(fast bounce-scroll)效果,但是它会阻止渲染直到滚动结束。
影响
- 从不滚动状态到滚动状态(反之亦然),因为要先初始化滚动状态才开始渲染,虽然很短暂,但也是有delay的,所以出现闪屏(公众号2期课程详情页闪屏问题)
- 列表滚动过程中,需要等到滚动结束之后,后面的元素才会渲染出来(公众号2期课程列表页下拉刷新元素出来慢的问题)
解决方案
- 启动硬件加速,可以用-webkit-transform: translate3d(0,0,0),这个hack可以解决大部分问题
- 用min-height,直接杜绝滚动状态改变,从而防止闪屏问题(已解决详情页闪屏问题)
ps: 【[机型兼容][IOS8]闪屏问题】的根本原因
[机型兼容][iOS] 部分图片不缓存
经过排查, 图片大于1M的情况下, 并且开启了crossOrigin, 就会导致浏览器不缓存该图片.
解决方法是:
- 图片大小减少
- 去掉crossOrigin
@ousiri 图片不缓存,有哪些机型有问题?
iOS~~~~
Listview 太长引起的手机性能问题
内存中存留的DOM结构太多,导致滚动的 Listview 后面,点击响应会延迟,甚至无响应。
解决方法是:
-
下拉滚动翻页过程中,对之前页码的数据进行隐藏。
向上滚动时,采取一定的策略将隐藏的数据显示var $lastHidden = $teacherList.find('li[data-show="hidden"]').last(), lastHiddenPage = $lastHidden.data('page'); var $midle = $teacherList.find('li[data-page="' + (lastHiddenPage + 2) + '"]').eq(4); if($midle && $midle.offset() && $midle.offset().top > $(document.body).scrollTop()){ // 页面中最后一个元素显示在屏幕中 // problem: 向上滑动过快,这里有卡顿 $teacherList.find('li[data-page="' + lastHiddenPage + '"]').css('visibility', 'visible').data('show', 'visible'); }
获取最后一个隐藏的元素,得到隐藏的页码,判断后2页中的第5条数据是否在屏幕中。
弹出框中的滚动事件冒泡导致body也滚动
如图所示,当弹出框内容在滚动时,如果滚动到边界,会导致页面内容也会跟着滚动。
- _尝试解决但失败的方案_:
(使用zepto)在弹出的对话框元素上捕获事件,并阻止冒泡(stopPropagation),虽然阻止冒泡后,在body上没有监测到touchmove事件,但是页面内容还是会被带着滚动。 - 成功解决方案一:
在显示对话框时,将html和body的height都设置为100%,overflow都设置为hidden,然后在对话框关闭时将html和body的height与overflow属性都设置为auto。
打开对话框和关闭对话框后分别执行的函数:
function lockBody() {
$body.css({
height: "100%",
overflow: "hidden"
});
$html.css({
height: "100%",
overflow: "hidden"
});
}
function unlockBody() {
$body.css({
height: "auto",
overflow: "auto"
});
$html.css({
height: "auto",
overflow: "auto"
});
}
这种方案最先想到,但这种方案比较麻烦,需要使用js在对话框显示与关闭时更改元素的css,性能会受影响。
- 成功解决方案二:
在body内加一层div.scroll-wrapper,这个div包含页面的所有显示内容但不包含弹出框,.scroll-wrapper和html还有body的height都为100%,html和body的overflow为hidden,.scroll-wrapper的overflow为scroll。让.scroll-wrapper的div来控制页面内容的滚动。因为弹出框是通过fix布局不属于.scroll-wrapper的子元素,所以滚动不会冒泡到.scroll-wrapper上。
DOM结构:
<body>
<div class="scroll-wrapper">
<div class="banner">
banner
</div>
<div class="content">
<p>p </p>
</div>
</div>
<div id="mask">
</div>
<div class="dialog">
<div class="dialog-head">
</div>
<div class="dialog-body">
<ul>
<li>aaaaaaaaa</li>
</ul>
</div>
<div class="dialog-foot">
<a href="javascript:;">确定</a>
<a class="close" href="javascript:;">关闭</a>
</div>
</div>
<script src="zepto.js" ></script>
<script src="index.js" ></script>
</body>
CSS:
.scroll-wrapper {
height: 100%;
width: 100%;
overflow: scroll;
}
html, body {
height: 100%;
overflow: hidden;
}
这种方法不需要使用js逻辑来控制,只用加一个div元素并设置相应的css进行控制。
测试源代码:https://github.com/coolriver/webTest/tree/master/mobileH5/dialogScroll
我是用的iscroll解决的上述问题
@chshouyu iscroll模拟滚动,自然就不会有这个问题了,只是iscroll在很多android机型下有性能上的影响,而且在ios下不如原生的流畅,所以除非是必须要用iscroll(比如:需要监听滚动事件等),才会将原生滚动换成iscroll。
这两种解决方案在ios上表现都不太好,ios上滚动没有惯性动画了啊。感觉这种方法搭配iscroll,根据操作系统选择使用的方法更好些?我最后用的也是iscroll
@banyaner 在实际业务中,确实需要根据场景做一些不同的处理。比如说浮层的场景,整个dom的场景都不一样,根据场景不同。另外不同平台的考虑也需要。总之,方案有这些,需要不同场景选择合适的方案。
[疑难问题]IOS 中微信浏览器中滚动事件触发多次,导致数据重复加载。
//滚动事件(安卓没有触发多次,IOS中一次滚动会触发多次事件)
$(".contain").scroll(function () {
if ($(this).scrollTop() + $(this).innerHeight() > $(this)[0].scrollHeight - 300
&& mySpace.oldScrollHeight < $(this)[0].scrollHeight) {
mySpace.oldScrollHeight=$(this)[0].scrollHeight;
console.log(mySpace.currentTabId + " scroll to bottom");
mySpace.getDataByTabId();
//alert("scroll to bottom"+mySpace.oldScrollHeight);
}
});