zoukankan      html  css  js  c++  java
  • html5移动端长按事件填坑历程

    背景:

    在h5页面,实现长按弹出上拉菜单,我们知道h5没有所谓的长按事件,有些UI组件库封装了长按事件,比如zepto的longtap

    在pc端有鼠标事件(mousedown,mousemove,mouseup),在h5有touch触摸事件(touchstart,touchmove,touchend)

    不能因为需要一个长按事件就引入一个库,这里我们就基于touch触摸事件来实现。

    touch事件群

    • touchstart事件:当手指触摸屏幕的时候触发, 一个手指触摸触发一次;
    • touchmove事件:当手指在屏幕上滑动的时候触发,滑动一下可能触发多次,是一个持续的过程
    • touchend事件: 当手指从屏幕上移开的时候触发;
    • touchcancel事件:当触摸点被中断时触发。例如在触摸过程中突然页面alert()一个提示框

         手指快速点击一个元素,会经过:touchstart  -> touchend --> click

         手指长按一个元素,会经过:touchstart  -> touchend

         手指滑动,会经过:touchstart  ->  touchmove(n次) -> touchend

         综上:

         1、click事件发生在touchstart和touchend之后,这也就是我们所说的移动端点击事件一般有300ms的延迟(可用tap事件替代)

         2、长按的过程是touchstart之后touchend之前,区分长按还是点击,可以根据时间判断,比如大于500ms是长按,小于500ms是点击

         3、如果在点击屏幕的时候手指滑动的话,是不会触发click事件的

     由以上结论,我们就可实现长按事件

     主要逻辑:

          1、在touchstart里定义延迟器,500ms后执行长按逻辑

          2、在touchend里取消延迟器,即在touchstart触发的500ms之内,如果手指从屏幕上移开,则不是长按

          3、在touchmove里取消延迟器,即如果手指在屏幕上滑动,则不是长按

    代码如下:

    <div  @touchstart="onTouchStart(d,$event)"
          @touchmove="onTouchMove($event)"
          @touchend="onTouchEnd">按钮</div>
    
    
    export default {
       data () {
          toucheX: 0,
          toucheY: 0,
          timeOutEvent: ''
       },
       methods: { 
         // 长按弹出上拉操作面板
        onTouchStart (data, e) {
          this.toucheX = e.targetTouches[0].screenX
          this.toucheY = e.targetTouches[0].screenY
          // 开启定时器前先清除定时器,防止重复触发
          this.timeOutEvent && clearTimeout(this.timeOutEvent)
    // 显示上拉面板
    this.timeOutEvent = setTimeout(() => {this.showActionSheet = true }, 500) e.preventDefault() // 阻止系统默认事件 }, onTouchMove (e) { const moveX = e.targetTouches[0].screenX const moveY = e.targetTouches[0].screenY // 解决vivo机型,手指没有move,touchmove事件仍然会调用而导致setTimeout被clear if (this.toucheX !== moveX || this.toucheY !== moveY) { // 手指滑动,清除定时器,中断长按逻辑 this.timeOutEvent && clearTimeout(this.timeOutEvent) } }, onTouchEnd () {
    // 清除定时器,结束长按逻辑
    this.timeOutEvent && clearTimeout(this.timeOutEvent)
    // 若手指离开屏幕,时间小于我们设置的长按时间,则为点击事件 }, } }

    注意:

    1、H5页面长按会触发系统的默认事件,ios和安卓表现不同,如下图。可以使用event.preventDefault()方法阻止后面默认事件的发生

          

    在touchstart中preventDefault,会导致click事件不触发和a链接点击没反应。可以使用tap代替click,但是a标签的话就不太方便了

    在touchmove中preventDefault,会阻止浏览器默认滚动

    2、在某些手机,比如vivo,没有move,但是touchmove事件仍然会触发

    在这种情况,可以根据touch的位置判断手指是否移动,来区分是点击长按或者是滑动

    在touchstart事件中记录touch时的x,y的坐标,然后在touchmove中,再判断touch的位置是否和touchstart中的一样的。

    注意,查看TouchEvent最好在谷歌模拟手机浏览器中查看,不要在真实手机浏览器查看,本人在真实手机浏览器console和alert都看不到详细的信息,疑惑了半天,发现真实手机浏览器虽然看不到信息,但是可以直接取值(TouchList是类数组对象)

    触屏事件的操作信息都存储在TouchEvent类型对象中,此对象属性较多,下面着重介绍下touches、targetTouches与changedTouches

       touches[只读]:手指触摸到屏幕上,所有触摸点的集合;

       targetTouchs[只读]:手指触摸到DOM元素(绑定事件的dom节点)上的触摸点的集合 

       changeTouches[只读]:表示自上次触摸事件以来发生改变的(和触摸事件对应的Touch 对象)

                对于 touchstart 事件, changedTouches是此次事件中新增加的触点。

                对于 touchmove 事件,changedTouches是和上一次事件相比较,发生了变化的触点。

          对于touchend事件,changedTouches 是刚触摸面离开的触点(最后一次离开屏幕的手指的Touch 对象)

          下图中有两个div,只对DIV2绑定了touchstart事件

       当手指第一次触摸到DIV2时,三个对象表示的都是一样的

       再放下第二根手指和第三根手指同时触摸DIV1DIV2时,

            此时touches对象表示的是第一根手指、第二根手指、第三根手指的信息

       此时targetTouches对象表示的是第一根手指和第三根手指的信息,因为绑定touch事件的节点为DIV2

       而changedTouches对象表示的是第二根手指和第三根手指的信息,因为第一根手指没有变化

     综上:

    touchmove时,如果手指从目标元素(绑定事件的dom节点)滑出,targetTouches还会有此触摸点信息

    当一个触摸点从目标元素离开,它的信息将从 touches、targetTouches里移除,但是changedTouches会保留此触摸点信息;

    当最后一个触摸点离开,touches、targetTouches变成空值,而changedTouches保留着最后一个离开的触摸点信息

     扩展:

    Touch.screenX:触点相对于屏幕左边沿的X坐标。只读属性。

    Touch.screenY:触点相对于屏幕上边沿的Y坐标。只读属性。

    Touch.clientX:触点相对于可见视区(visual viewport)左边沿的X坐标。不包括任何滚动偏移。只读属性。

    Touch.clientY:触点相对于可见视区(visual viewport)上边沿的Y坐标。不包括任何滚动偏移。只读属性。

    Touch.pageX:触点相对于HTML文档左边沿的X坐标。当存在水平滚动的偏移时,这个值包含了水平滚动的偏移。只读属性。

    Touch.pageY:触点相对于HTML文档上边沿的Y坐标。当存在水平滚动的偏移时,这个值包含了垂直滚动的偏移。只读属性。

  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/caofeng11/p/14213616.html
Copyright © 2011-2022 走看看