首页 > 代码库 > 总结在移动端碰到的坑

总结在移动端碰到的坑

一、安卓设备的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

 

总结在移动端碰到的坑