vue 自定义事件(移动端上下左右滑动长按)

新建一个js 文件 内容如下

/**
 * 处理 移动设备上的 点击、长按、左右上下滑动 事件
 *
 * =========================================
 * 导出了7个自定义指令:
 *  v-tap: tap点击事件
 *  v-swipe: swipe滑动事件
 *  v-swipeleft: swipeleft左滑事件
 *  v-swiperight: swiperight右滑事件
 *  v-swipedown: swipedown下滑
 *  v-swipeup: swipeup上滑
 *  v-longtap: longtap长按
 * =========================================
 *
 * =========================================
 * 包含四个参数
 * stop 阻止冒泡
 * prevent 阻止默认事件
 * self 只当在 event.target 是当前元素自身时触发处理函数
 * once 执行一次后解绑
 *
 * @example v-tap.stop.prevent.self.once
 * =========================================
 *
 * =========================================
 * 事件绑定有两种方式
 * @example
 *  1. v-tap="showDialog" 绑定一个方法对象
 *  2. v-tap="{fn:click123, param1:1, param2:2, param3:{aaa:'123'} ...}"
 *      绑定一个JSON字面量,fn是执行的方法,后边的是需要传递的参数
 * 事件回调参数
 * @param 第一个参数是event,事件对象
 * @param 第二个参数是 binding.value,也就是v-tap=""双引号中的部分(如示例2,第二个参数就是 {fn:click123, param1:1, param2:2, param3:{aaa:'123'} ...})
 * =========================================
 *
 * @update
 *  1. 根据MUI进行了滑动事件的判断修正
 *  2. 根据TouchEvent修正了点击位置的判断
 *
 */

import Vue from 'vue';

/**
 * vue上点击事件处理类
 */
class VueTouch {
  /**
   * @param el
   * @param binding
   * @param type
   */
  constructor(el, binding, type) {
    
    let g = this;
    
    g.obj = el;
    g.binding = binding;
    g.touchType = type;
    
    g.firstTouchPosition = {x: 0, y: 0};
    g.firstTouchTime = 0;
    g.callBack = typeof(binding.value) === "object" ? binding.value.fn : binding.value;
    
    g.moved = false;
    g.leaved = false;
    g.longTouched = false;
    
    // 事件监听回调集合
    let _listener = Object.create(null);
    
    // 事件方法
    let _listen = (type) => {
      return function (e) {
        let {stop, prevent, self, once} = g.binding.modifiers;
        
        // 配置判断
        if (stop) e.stopPropagation();
        if (prevent) e.preventDefault();
        if (once) g.obj.removeEventListener("touch" + type, _listener[type]);
        if (self && e.target !== e.currentTarget) return;
        
        g[type](e);
      }
    };
    
    _listener.start = _listen('start');
    _listener.end = _listen('end');
    _listener.move = _listen('move');
    
    this.obj.addEventListener("touchstart", _listener.start, false);
    this.obj.addEventListener("touchend", _listener.end, false);
    this.obj.addEventListener("touchmove", _listener.move, false);
  }
  
  start(e) {
    
    let g = this;
  
    // 初始化点击状态
    g.moved = false;
    g.leaved = false;
    g.longTouched = false;
    
    g.firstTouchPosition = g.getMultiCenter(e.changedTouches);
    g.firstTouchTime = e.timeStamp;
    g.time = setTimeout(function () {
      if (!g.leaved && !g.moved) {
        g.touchType === "longtap" && g.callBack(e, g.binding.value);
        g.longTouched = true;
      }
    }.bind(g), 1000);
  }
  
  end(e) {
    
    let g = this;
    
    let {x, y} = g.getMultiCenter(e.changedTouches);
    let _disX = x - g.firstTouchPosition.x;
    let _disY = y - g.firstTouchPosition.y;
    let _dis = Math.sqrt(_disX * _disX + _disY * _disY);
    let _timeDis = e.timeStamp - g.firstTouchTime;
    
    clearTimeout(g.time);
    
    let _angle = this.getAngle(_disX, _disY);
    
    if (_dis > 18 && _timeDis < 300) {
      g.touchType === "swipe" && g.callBack(e, g.binding.value);
      if (_angle >= 60 && _angle <= 120)
        g.touchType === "swipedown" && g.callBack(e, g.binding.value);
      if (_angle <= -60 && _angle >= -120)
        g.touchType === "swipeup" && g.callBack(e, g.binding.value);
      if (_angle <= 20 && _angle >= -20)
        g.touchType === "swipeleft" && g.callBack(e, g.binding.value);
      if ((_angle <= -160 && _angle >-180) || (_angle >= 160 && _angle <= 180))
        g.touchType === "swiperight" && g.callBack(e, g.binding.value);
    } else {
      if (!g.longTouched && !g.moved) {
        g.touchType === "tap" && g.callBack(e, g.binding.value);
        g.leaved = true;
      }
    }
  }
  
  move() {
    this.moved = true;
  }
  
  /**
   * 获取点击集合的中心坐标
   * @param touches touch对象集合
   * @return {{x: number, y: number}}
   */
  getMultiCenter(touches) {
    
    let g = this, x = 0, y = 0;
    
    const _length = touches.length;
    
    for (let i = 0; i < _length; i++) {
      x += touches[i].pageX;
      y += touches[i].pageY;
    }
    
    return {
      x: Math.round(x / _length),
      y: Math.round(y / _length)
    };
  };
  
  getAngle(disX, disY) {
    let g = this;
    
    if (typeof disX !== 'number' || typeof disY !== 'number')
      return 45;
    
    return Math.atan2(disY, disX) * 180 / Math.PI;
  }
}


Vue.directive("tap", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "tap");
  }
});
Vue.directive("swipe", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "swipe");
  }
});
Vue.directive("swipeleft", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "swipeleft");
  }
});
Vue.directive("swiperight", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "swiperight");
  }
});
Vue.directive("swipedown", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "swipedown");
  }
});
Vue.directive("swipeup", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "swipeup");
  }
});
Vue.directive("longtap", {
  bind: function (el, binding) {
    new VueTouch(el, binding, "longtap");
  }
});

2.在哪用 就在哪引

import vueTouch from "../../vueTouch.js";

3.绑定事件

<div v-swipeup="doSomeThing"></div>

4.处理事件

methods: {
	doSomeThing() {}
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值