首页 > 代码库 > 总结在移动端碰到的坑
总结在移动端碰到的坑
一、安卓设备的select options的坑,尽量使用各浏览器内核都支持的api
在添加 OPTION 元素时
- 如果需要向指定索引前插入 OPTION,可以使用 options.add(option, index);
- 如果需要向 SELECT 尾部添加 OPTION,可以使用 options.add(option);
- 如果需要向指定索引处添加(或更改) OPTION,可以使用 options[index] = option。
在删除 OPTION 元素时
- 如果想删除指定索引处的 OPTION 元素,可以使用 select.remove(index) 或 options[index] = null;
- 如果想删除某个指定的 OPTION 元素,可以使用 select.remove(option);
- 如果想删除 SELECT 中所有 OPTION,可以使用 select.length = 0 或 options.length = 0。
二、移动端click事件300ms延迟
click事件,在移动端,会经过300ms的延迟后才触发。原因是,移动浏览器提供一个特殊的功能:双击(double tap)放大,用户碰触页面之后,需要等待一段时间来判断是不是双击(double tap)动作,而不是立即响应单击(click),等待的这段时间大约是300ms。那么怎么消除这个300ms延迟呢?
1.使用fastclick插件,会消除所有click事件的延迟,不推荐使用插件来解决这个问题
2.不用click事件,用移动设备提供的原生touch事件,或某些移动端手势库提供的tap事件。移动端touch事件提供了 touchstart
、 touchmove
、 touchend等,
对于简单的页面,可以把 touchstart
或者 touchend
当作tap来用,这样可以解决300ms延迟问题,但并不完美,比如手指接触目标元素,按住不放,慢慢移出响应区域,依然会触发 touchstart
事件对应的事件处理器(本不应该触发),touchend也有类似的问题,所以,如果想模拟原生App的点击事件,需要自己封装一套tap事件,或者使用手势库的tap事件,tap事件原理也非常简单,是由touchstart和touchend组合而成,首先要判断touchend和touchstart的偏移距离,然后阻止掉touchend事件300ms之后触发的click事件,并且始终以touchend事件作为触发的必要条件,下面是个demo:
function tap(node,callback,scope) { node.addEventListener(TOUCHSTART, function(e) { x = e.touches[0].pageX; y = e.touches[0].pageY; }); node.addEventListener(TOUCHEND, function(e) { e.stopPropagation(); e.preventDefault(); var curx = e.changedTouches[0].pageX; var cury = e.changedTouches[0].pageY; if (Math.abs(curx - x) < 6 && Math.abs(cury - y) < 6) { callback.apply(scope, arguments); } }); }
下面是zepto的tap事件实现源码:
if (deltaX < 30 && deltaY < 30) { tapTimeout = setTimeout(function() { var event = $.Event(‘tap‘) event.cancelTouch = cancelAll touch.el.trigger(event) if (touch.isDoubleTap) { if (touch.el) touch.el.trigger(‘doubleTap‘) touch = {} }else { touchTimeout = setTimeout(function() { touchTimeout = null if (touch.el) touch.el.trigger(‘singleTap‘) touch = {} }, 250) } }, 0); }
三、点击穿透
如果某个返回按钮的位置,恰好在要返回的这个页面的带有href属性的a标签的范围内,在点击返回按钮后,页面快速切换到有a标签的页面,300ms后触发了click事件,从而触发了a标签的意外跳转,这个就是典型的点击穿透问题。罪魁祸首其实就是a标签跳转默认是click事件触发,而移动端的touch事件触发之后,依然会在300ms后触发click事件。解决办法其实在上面一条已经提到了。
1.就是消费掉touch事件完成后的click事件。
2.不要混用touch和click事件。显然不可能都绑定click事件,因为要解决300ms延迟问题(除了fastclick),那么只能都绑定touch事件,这样click事件永远不会被触发。
综上二条,最好的办法就是自己封装一个tap事件,并且自己阻止掉300ms后的click事件,完美解决。
注意:zepto并没有阻止click事件,所以使用zepto的tap事件依然会导致点击穿透问题,你需要手动添加 e.preventDefault() 来阻止click事件。
四、移动端整体布局
移动端的整体布局一般来说可以分为上中下三个部分,分别为 header、main、footer,其中header、footer 是固定高度,分别固定在页面顶部和页面底部,而 main 是页面展示主体内容的部分,并且可以滚动。要实现这种布局,有两种办法:
1.最容易想到的就是header和footer为fixed,body最小高度为一屏,超出则滚动。这种布局有个优点,在ios的safari上页面的地址栏会随着 body 的滚动隐藏起来,缺点就是fixed在有input的页面会有各种兼容性问题(经测试,在固定到主屏幕并且去掉导航栏的情况下fixed有bug,在安卓或者ios的webview中也会有bug,移动端的各种浏览器中是没有问题的),并且全局滚动不同的tab之间共享一个滚动条,显然不是我们想要的。
2.采取内滑的策略。具体的实现方式可能略有不同,但思路都是在元素内部滚动,而不是body。比如可以设置header和footer为absolute,main也为absolute,并且overflow-y为auto,或者用弹性布局的方式。在移动端元素内滑动会有不流畅的问题,建议加上-webkit-overflow-scrolling: touch,这样就能愉快的滚动了。这种布局的优点就是避免了使用fixed,而且每个局部滚动拥有自己的滚动条,缺点就是移动端浏览器中input框的光标闪烁问题(在滚动页面的时候,光标闪烁会有来不及重绘的情况出现,导致光标错位,不跟随input框闪烁)
五、input 的 compositionstart 和 compositionend 事件
在input中输入中文的时候,在没有选定文字前,输入的每一个拼音字母也会触发input事件,这显然不是我们想要的。我们需要 compositionstart 和
compositionend 事件来处理这个问题。compositionstart会在用户开始进行非直接输入的时候触发,compositionend会在点选候选词或者点击「选定」按钮之后触发。我们可以在compositionstart的时候将input事件上锁,让其不执行,在compositionend的时候再解锁,注意:compositionend 事件是在 input 事件后触发的。
六、移动端 1px border 实现
由于设备高分辨率屏的原因,逻辑像素的 1px 的 border 在移动设备上会用两个或三个物理像素来表示,所以看起来会感觉很粗。解决方案有很多,但兼容性最好的方案是用伪元素的 box-shadow 或 border 实现 border,然后用 transform: scale(.5) 缩小到原来的一半。具体如下:
.block { width: 100px; height: 100px; margin: 10px; position: relative; /*border: 1px solid red;*/ } .block:before { content: ‘‘; position: absolute; transform-origin: 0 0; top: 0; left: 0; width: 200%; height: 200%; border: 1px solid red; transform: scale(.5); }
七、一些小坑
1.format-detection
<meta name="format-detection" content="telephone=no">
默认情况下,设备会自动识别任何可能是电话号码的字符串。设置telephone=no可以禁用这项功能。
2.禁止复制、选中文本
user-select: none;
3.长时间按住页面出现闪退或禁止 iOS 弹出各种操作窗口
-webkit-touch-callout: none;
4.ios或安卓设备input等元素的特殊样式
-webkit-appearance: none;
5.ios或android下触摸元素时出现半透明灰色遮罩
-webkit-tap-highlight-color:rgba(255,255,255,0)
6.移动端伪类 :active 不起作用
document.addEventListener(‘touchstart‘,function(){},false);
7.启用硬件加速使动画更流畅
transform: translate3d(0, 0, 0);
8.旋转屏幕时,字体大小调整的问题
-webkit-text-size-adjust:100%;
9.transition闪屏
设置子元素以3D的方式呈现
-webkit-transform-style: preserve-3d;
设置进行转换的元素的背面在面对用户时是否可见
-webkit-backface-visibility:hidden;
10.CSS3 rotateY transition 在safari上有bug
当前转动的元素,在其上有元素覆盖它时,或在其下有元素被它覆盖时,会出现如下bug:
建议设置transform: translateZ(-1000px);
11.移动端选择相片
<input type=file accept="image/*">
一定要显示的声明accept接收的类型
参考文献:http://www.cnblogs.com/strick/p/5161660.html
https://zhuanlan.zhihu.com/p/26141351
https://zhuanlan.zhihu.com/p/24837233
http://www.cnblogs.com/wangpenghui522/p/5398137.html
http://www.cnblogs.com/liulinjie/p/5776337.html
http://www.haorooms.com/post/phone_web
总结在移动端碰到的坑