查看: 2465|回复: 0

[HTML代码] 关于移动端tap事件的实现

发表于 2018-2-12 08:00:01

在做移动端web开发时,常遇到click事件点击延迟问题,直接使用click事件就会造成不好的体验,但是我们可以用移动端的touch事件来模拟click事件,于是我花了些时间做了一个tap.js,下面附上代码。

js:

  1. /*!
  2. * tap.js v1.2.2
  3. */
  4. ;(function (factory) {
  5. if (typeof define === 'function' && define.amd) {
  6. define(function(){return factory;});
  7. }else if (typeof exports == "object") {
  8. module.exports = factory;
  9. }else {
  10. window.tap = factory;
  11. }
  12. }(function(){
  13. var arg = arguments,
  14. doc = window.document,
  15. els = arg[0] == doc ? [doc]:doc.querySelectorAll(arg[0]),
  16. isTouch = "ontouchend" in doc,
  17. len = els.length,
  18. i = 0,
  19. isEntrust = typeof arg[1]== 'string',
  20. isMulti = typeof arg[1]== 'object';
  21. if(len == 0){return false;}
  22. while (i < len){
  23. if(isTouch){
  24. var o = {};
  25. els[i].addEventListener('touchstart',function(e){
  26. var t = e.touches[0];
  27. o.startX = t.pageX;
  28. o.startY = t.pageY;
  29. o.sTime = + new Date;
  30. });
  31. els[i].addEventListener('touchend',function(e){
  32. var t = e.changedTouches[0];
  33. o.endX = t.pageX;
  34. o.endY = t.pageY;
  35. if((+ new Date)-o.sTime<300){
  36. if(Math.abs(o.endX-o.startX)+Math.abs(o.endY-o.startY)<20){
  37. handler(e,arg,this);
  38. }
  39. }
  40. o = {};
  41. });
  42. }else{
  43. els[i].addEventListener('click',function(e){
  44. handler(e,arg,this);
  45. });
  46. }
  47. i ++;
  48. }
  49. function handler(e,arg,that){
  50. if(e.target.href){
  51. return window.location = e.target.href;
  52. }
  53. if(isEntrust){
  54. if(equal(e,arg[1])){
  55. prevent(e);
  56. arg[2].call(e.target,e);
  57. }
  58. }else if(isMulti){
  59. for(key in arg[1]){
  60. if(equal(e,key)){
  61. prevent(e);
  62. arg[1][key].call(e.target,e);
  63. break;
  64. }
  65. }
  66. }else{
  67. prevent(e);
  68. arg[1].call(that,e);
  69. }
  70. }
  71. function equal(e,el){
  72. var flag = false;
  73. if(el.indexOf('.') != -1 && e.target.className == el.replace('.','')){
  74. flag = true;
  75. }else if(el.indexOf('#') != -1 && e.target.id == el.replace('#','')){
  76. flag = true;
  77. }else if(e.target.nodeName.toLocaleLowerCase() == el){
  78. flag = true;
  79. }
  80. return flag;
  81. }
  82. /*preventDefault不执行则会引起触发失效bug,
  83. *但不必要则不执行。
  84. */
  85. function prevent(e){
  86. var tagName = e.target.tagName.toLocaleLowerCase();
  87. if(tagName != 'select' && tagName != 'input' && tagName != 'textarea'){
  88. doc.activeElement.blur();
  89. e.preventDefault();
  90. }
  91. }
  92. }))
复制代码

demo.html(这里可以直接运行测试)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1.0, user-scalable=0">
  6. <title>tap demo</title>
  7. <style type="text/css">
  8. h4{margin: 10px 0;}
  9. </style>
  10. </head>
  11. <body>
  12. <h3>直接调用</h3>
  13. <div>
  14. <button class="button">tap1</button>
  15. <button class="button">tap2</button>
  16. <button class="button">tap3</button>
  17. <button class="button">tap4</button>
  18. <button class="button">tap5</button>
  19. </div>
  20. <hr>
  21. <h3>事件委托</h3>
  22. <div id="test">
  23. <button class="button2">tap1</button>
  24. <button class="add">add</button>
  25. <button class="doc">document</button>
  26. </div>
  27. <hr>
  28. <h3>事件冒泡</h3>
  29. <h4>正常冒泡</h4>
  30. <div id="parent">
  31. parent<br><br>
  32. <button class="son">son</button>
  33. </div>
  34. <h4>阻止冒泡</h4>
  35. <div id="parent2">
  36. parent2<br><br>
  37. <button class="son2">son2</button>
  38. </div>
  39. <h3>阻止默认动作</h3>
  40. <form action="">
  41. <button class="submit" type="submit">提交</button>
  42. </form>
  43. <h3>代码优化</h3>
  44. <h4>快速跳转</h4>
  45. <div class="a-box">
  46. <a href="https://github.com/weijhfly/tap"><button>里面有子元素</button></a>
  47. <a href="https://github.com/weijhfly/tap">没有子元素</a>
  48. </div>
  49. <br>
  50. <input type="text" placeholder="测试焦点是否正常">
  51. <h4>同时指定多个事件</h4>
  52. <button class="e1">事件1</button>
  53. <button class="e2">事件2</button>
  54. <button class="e3">事件3</button>
  55. <!-- layer.js仅做弹出演示 -->
  56. <script src="https://weijhfly.github.io/js/layer/layer.js"></script>
  57. <script src="https://weijhfly.github.io/js/tap.js"></script>
  58. <script>
  59. //直接调用
  60. tap('.button',function(e){
  61. console.log(e);
  62. var event = "ontouchend" in document? 'tap':'click';
  63. layer.msg(event+' : '+this.innerText);
  64. })
  65. // 事件委托 event delegation
  66. tap('#test','.button2',function(){
  67. var event = "ontouchend" in document? 'tap':'click';
  68. layer.msg(event+' : '+this.innerText);
  69. })
  70. var i = 0;
  71. tap('#test','.add',function(e){
  72. console.log(e);
  73. i ++;
  74. var test = document.getElementById("test");
  75. var button = document.createElement("button");
  76. button.className = 'button2';
  77. button.innerHTML = "button "+i;
  78. test.insertBefore(button,test.childNodes[0]);
  79. })
  80. tap(document,'.doc',function(){
  81. layer.msg('doc');
  82. })
  83. /*
  84. 阻止冒泡 stop propagation
  85. 在事件委托中仅能阻止委托元素对上层的冒泡
  86. */
  87. tap('#parent',function(){
  88. setTimeout(function() {
  89. layer.msg('parent');
  90. }, 100);
  91. })
  92. tap('.son',function(){
  93. layer.msg('son');
  94. })
  95. // 阻止冒泡
  96. tap('#parent2',function(){
  97. setTimeout(function() {
  98. layer.msg('parent2');
  99. }, 100);
  100. })
  101. tap('.son2',function(e){
  102. e.stopPropagation();
  103. layer.msg('son2');
  104. })
  105. /*
  106. 阻止默认动作
  107. 同上,事件委托中仅能阻止委托元素的默认动作
  108. 注意:在移动端默认执行e.preventDefault();
  109. */
  110. tap('.submit',function(e){
  111. e.preventDefault();
  112. e.stopPropagation();
  113. layer.msg('无法提交');
  114. })
  115. /*
  116. * 代码优化
  117. */
  118. //跳转 **存在href属性
  119. tap(document,'a');
  120. // 通过委托实现多个事件 **默认不能重复,重复只执行第一个
  121. tap(document,{
  122. '.e1':function(){
  123. layer.msg(this.innerText);
  124. },
  125. '.e2':function(){
  126. layer.msg(this.innerText);
  127. },
  128. '.e3':function(){
  129. layer.msg(this.innerText);
  130. }
  131. });
  132. </script>
  133. </body>
  134. </html>
复制代码

github:https://github.com/weijhfly/tap
有兴趣的可以看下,另外还有vue v-tap指令版的https://github.com/weijhfly/vue-tap,欢迎关注。

此外,在移动端解决点击延迟问题,还是比较推荐fastclick,兼容性较好且方便使用,不过相对而言模拟tap事件体积较小,也可以拿来练手了。



回复

使用道具 举报