1

这两天做H5页面,使用swiper+iscroll+fastClick,并没有用swiper提供的tap和click事件,自己在元素上bind,因为回调函数是统一处理,就没用swiper的tap,后面发现即使是使用了swiper提供的,也是会有问题,本人用的ios设备,做完一切流畅,但是提交给测试确发现安卓有个问题,如题。

swiper v4.5.0

研究了一下swiper源码,发现初始化的时候会给容器注册一个click事件

clipboard.png

这里是用来判断用户当前是否触发touchmove事件,如果是touchmove那么就阻止所有bind元素的click事件,这个逻辑没错啊,于是继续在模拟器中调试。

打了各种断点调试,发现swiper绑定的touchend中代码逻辑执行顺序在两个客户端中是不一样的,神奇。

clipboard.png

如上图,ios中先执行了onClick方法,后执行Utils.nextTick的回调;android则相反,先执行nextTick的回调;然后看了下,swiper是怎么封装的回调Utils.nextTick

clipboard.png

??? 好像没问题啊,eventLoop执行顺序对的啊。难道是安卓上setTimeout和event执行顺序异于其他浏览器。

敲段代码测试一下(注意,下面这段代码直接用浏览器打开,执行顺序是相同的,但是,找个容器去挂载,比如tomcat,执行顺序的问题就出来了):

<!DOCTYPE html>
<html>

<head>
  <title>touchend-click-setTimeout</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta name="viewport"
    content="initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no,target-densitydpi = medium-dpi">
  <meta name="format-detection" content="telephone=no">
  <meta name="apple-touch-fullscreen" content="YES">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <link rel="stylesheet" type="text/css" href="./lib/swiper.css" />
  <link rel="stylesheet" type="text/css" href="./lib/pullToRefresh.css" />
  <style>
    body,html{
      padding: 0;
      margin: 0;
      border: 0;
    }
    .btn{
      height: 50px;
      line-height: 50px;
      text-align: center;
      background: #ccc;
      color: #fff;
      width: 200px;
      margin: 0 auto;
    }
  </style>
</head>

<body>
  <section id="wrapper">
    <ul style="background:#F3F4F6;">
      <div class="btn">touchend-btn</div>
    </ul>
  </section>
</body>
<script type="text/javascript" src="./lib/jquery.min.js"></script>
<!-- <script type="text/javascript" src="./lib/fastclick.js"></script>
<script type="text/javascript" src="./lib/iscroll.js"></script>
<script type="text/javascript"  src="./lib/pullToRefresh.js"></script>
<script type="text/javascript" src="./lib/swiper.js"></script>
<script type="text/javascript" src="./lib/vconsole.min.js"></script> -->
<script>
  // 原生默认的执行顺序:
  // ios执行顺序: touchstart -> touchend -> click -> setTimeout
  // android执行顺序: touchstart -> touchend -> setTimeout -> click

  // FastClick.attach(document.body);
  // refresher.init({
  //   id: "wrapper",
  //   pullDownAction: function () {
  //   },
  //   pullUpAction: function () { }
  // });
  $('.btn').on('touchstart',function(){
    console.log('touchstart');
  });
  $('.btn').on('touchmove',function(){
    console.log('touchmove');
  });
  $('.btn').on('touchend',function(){
    console.log('touchend');
    setTimeout(function(){
      console.log('touchend:setTimeout');
    },0);
  });
  $('.btn').on('click',function(){
    console.log('click');
  });
</script>

</html>

结果如下
ios执行顺序: touchstart -> touchend -> click -> setTimeout
android执行顺序: touchstart -> touchend -> setTimeout -> click

到这里我就没继续往下找原因了,直接修改,解决问题。

clipboard.png

不知道有没有大佬能帮忙看下,为啥ios和安卓执行顺序会有这种出入?望告知

另附赠一个问题吧,如果你用华为7S的部分机型进行测试,会发现,永远都无法点击自己bind的事件。因为使用了iscroll以后touchmove事件变得极其敏感,所有的click事件触发之前,都会触发touchmove。按照swiper的逻辑,一旦触发touchmove之后,所有的click都被阻止冒泡,就会出现上面说的问题,解决方案如下图:

clipboard.png

增加上图这个判定的即可。


南山
32 声望0 粉丝