要实现手指的 tap 动作,首先找到的应该是 vue-touch 插件,项目地址:Github,其基于 hammerjs,能除了点击以外,还能监听按住、滑动、双指收缩、双指旋转等动作,十分强大,但是没有对事件修饰进行定义,即无法阻止事件冒泡。
我找到另一个 tap 插件,来自 MeCKodo 的 vue-tap,项目地址:Github,十分简洁的一个插件,扩展功能也比较方便,有提供stop和prevent修饰符,所以我用了它。
修改需要
由于vue-tap提供的stop和prevent修饰符会在touchstart时就禁止了冒泡,导致我项目中使用的iscroll滚动会失效,于是我自定义了self修饰符,用于一旦被tap方法响应过,将不再进行向应的伪防冒泡修饰符,以及用于监控长按的long修饰符。
我修改的四个代码段如下:
监听的touchstart动作,增加全局变量tapDone用于记录tap是否已被触发过,longEnable用于记录长按是否有效,longTimer用于记录长按计时器
我本来是用self代替window的,毕竟全局变量有可能造成污染,但我tap动作中有路由切换动作,插件被重新加载后self中所有变量都会被重置,造成变量防冒泡失败,所以,最后我还是用了全局变量
this.el.addEventListener("touchstart",function(e) {
// 增加self修饰符-start by COoL
if(self.modifiers.self && window.tapDone)
return;
window.tapDone = true;
setTimeout(function(){
window.tapDone = false;
},200);
// 增加self修饰符-end
// 加入long修饰符实现长按动作-start by COoL
if (self.modifiers.long) {
window.longEnable = true;
window.longTimer = setTimeout(() => {
self.touchend(e,self,fn);
}, 600)
}
// 加入long修饰符实现长按动作-end
if(self.modifiers.stop)
e.stopPropagation();
if(self.modifiers.prevent)
e.preventDefault();
self.touchstart(e,self);
},false);
增加touchmove的监听,用于令长按无效
this.el.addEventListener("touchmove",function(e) {
window.longEnable = false;
},false);
修改isTap方法,把boolean返回值改为int,因为要增加长按类型
isTap : function() {
var self = this;
if(self.el && self.el.disabled){
return 0; // 原为false
}
var tapObj = this.tapObj;
if (Math.abs(tapObj.distanceX) >= 2 || Math.abs(tapObj.distanceY) >= 2) {
// 手指有移动,作废
return 0;
} else if (this.time < 150) {
// 快速点击
return 1;
} else if (this.time >= 600) {
// 长按
return 2;
} else {
// 时间有误,作废
return 0;
}
},
修改touchend方法,清空长按计时,判断点击还是长按,是否有效
touchend : function(e,self) {
var touches = e.changedTouches[0];
var tapObj = self.tapObj;
self.time = +new Date() - self.time;
tapObj.distanceX = tapObj.pageX - touches.pageX;
tapObj.distanceY = tapObj.pageY - touches.pageY;
// 加入long修饰符实现长按动作-start by COoL
// 清除长按计时
clearTimeout(window.longTimer)
// 获取是否长按或无效
var tapType = self.isTap(tapObj);
if (tapType === 0) {
// 无效
return;
}
if (tapType === 1) {
// 短击
self.handler(e);
return;
}
if (self.modifiers.long && tapType === 2 && window.longEnable) {
// 允许长按且是长按且首次触发且未移动过
window.longEnable = false;
self.handler(e, true)
return;
}
// 加入long修饰符实现长按动作-end
}
最后,看看调用的方法
v-tap.self.long="goOrDel($index, $event)"
self使冒泡无效,long使允许长按,而goOrDel方法中,$event.isLong将用于区分短击还是长按
goOrDel: function (ind, e) {
if (e.isLong) {
// 长按...
} else {
// 短击...
}
}
vue-tap-click.js文件如下
/**
* Created by 二哲 on 15/12/6.
*/
/*
* 不带参数指令
* v-tap=handler
* or
* 带参数指令
* v-tap=handler($index,el,$event)
*
* !!!新增!!!
* 把tapObj对象注册在原生event对象上
* event.tapObj拥有6个值
* pageX,pageY,clientX,clientY,distanceX,distanceY
* 后面2个分别的手指可能移动的位置(以后可用于拓展手势)
*
* */
;(function() {
var vueTap = {};
vueTap.install = function(Vue) {
Vue.directive("tap", {
isFn : true,
acceptStatement : true,
bind : function() {
//bind callback
},
update : function(fn) {
var self = this;
self.tapObj = {};
if(typeof fn !== "function") {
return console.error("The param of directive "v-tap" must be a function!");
}
self.handler = function(e, isLong) { //This directive.handler
e.tapObj = self.tapObj;
// 用全局变量记录是否长按 -start
if (isLong) {
e.isLong = true
}
// 用全局变量记录是否长按 -end
fn.call(self,e);
};
if(self.isPC()) {
self.el.addEventListener("click",function(e) {
e.preventDefault();
fn.call(self,e);
},false);
} else {
this.el.addEventListener("touchstart",function(e) {
// 增加self修饰符-start by COoL
if(self.modifiers.self && window.tapDone)
return;
window.tapDone = true;
setTimeout(function(){
window.tapDone = false;
},200);
// 增加self修饰符-end
// 加入long修饰符实现长按动作-start by COoL
if (self.modifiers.long) {
window.longEnable = true;
window.longTimer = setTimeout(() => {
self.touchend(e,self,fn);
}, 600)
}
// 加入long修饰符实现长按动作-end
if(self.modifiers.stop)
e.stopPropagation();
if(self.modifiers.prevent)
e.preventDefault();
self.touchstart(e,self);
},false);
this.el.addEventListener("touchmove",function(e) {
//e.preventDefault();
window.longEnable = false;
},false);
this.el.addEventListener("touchend",function(e) {
//e.preventDefault();
self.touchend(e,self,fn);
},false);
}
},
unbind : function() {},
isTap : function() {
var self = this;
if(self.el && self.el.disabled){
return 0; // 原为false
}
var tapObj = this.tapObj;
if (Math.abs(tapObj.distanceX) >= 2 || Math.abs(tapObj.distanceY) >= 2) {
// 手指有移动,作废
return 0;
} else if (this.time < 150) {
// 快速点击
return 1;
} else if (this.time >= 600) {
// 长按
return 2;
} else {
// 时间有误,作废
return 0;
}
},
isPC : function() {
var uaInfo = navigator.userAgent;
var agents = ["Android", "iPhone", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var i = 0; i < agents.length; i++) {
if (uaInfo.indexOf(agents[i]) > 0) { flag = false; break; }
}
return flag;
},
touchstart : function(e,self) {
var touches = e.touches[0];
var tapObj = self.tapObj;
tapObj.pageX = touches.pageX;
tapObj.pageY = touches.pageY;
tapObj.clientX = touches.clientX;
tapObj.clientY = touches.clientY;
self.time = +new Date();
},
touchend : function(e,self) {
var touches = e.changedTouches[0];
var tapObj = self.tapObj;
self.time = +new Date() - self.time;
tapObj.distanceX = tapObj.pageX - touches.pageX;
tapObj.distanceY = tapObj.pageY - touches.pageY;
// 加入long修饰符实现长按动作-start by COoL
// 清除长按计时
clearTimeout(window.longTimer)
// 获取是否长按或无效
var tapType = self.isTap(tapObj);
if (tapType === 0) {
// 无效
return;
}
if (tapType === 1) {
// 短击
self.handler(e);
return;
}
if (self.modifiers.long && tapType === 2 && window.longEnable) {
// 允许长按且是长按且首次触发且未移动过
window.longEnable = false;
self.handler(e, true)
return;
}
// 加入long修饰符实现长按动作-end
/*
if (self.isTap(tapObj)){
self.handler(e);
*/
}
});
};
if (typeof exports == "object") {
module.exports = vueTap;
} else if (typeof define == "function" && define.amd) {
define([], function(){ return vueTap })
} else if (window.Vue) {
window.vueTap = vueTap;
Vue.use(vueTap);
}
})();
[vue.js框架]vue.js实现手指点击事件 v-tap ,自定义 self 与 long 修饰符
http://m.bbyears.com/wangyezhizuo/99355.html
推荐访问: