最近在复查前辈的代码时,发现很多需要长按实现某种功能的地方都是用 onclick 替代的,原以为长按也是点击的一种形式,在做过数次测试后,那脸打得 pia、pia、pia,便有了自己封装一个长按功能的想法。
社会我猪哥,人不狠话也不多。说干就干!
思路分析
移动端的点击功能(PC端也一样),分为手指按下(touchstart)和抬起(touchend),间隔短;而长按功能的“长”字,便可以在“间隔”之上做文章,手指按下和抬起间隔时间达到某个阈值,就称之为“长按”。
代码环节
有了上述分析, 窃以为将间隔时间定为 700 毫秒也是可以的。于是乎,就有了如下代码,仅供参考:
(function(win) {
/**
* 长按功能,长按 700ms 以上即可调用回调方法
*
* @class
*/
class LongPress {
/**
* 构造器
*
* @public
* @param {String} el 需要长按的 DOM 节点名
* @param {function} callback 长按触发的回调函数
*/
constructor(el, callback) {
this.el = document.querySelector(el);
// 初始化开始时间
this.startTime = 0;
// 初始化结束时间
this.endTime = 0;
this.init(callback);
}
/**
* 初始化
*
* @private
* @param {function} callback 回调函数
*/
init(callback) {
this.touchstart();
this.touchend(callback);
}
/**
* 手指按下时为 startTime 赋值当前时间
*
* @private
*/
touchstart() {
this.el.addEventListener('touchstart', function(event) {
// 清除默认行为
event.preventDefault();
// 记录手指按下的时间戳
this.startTime = new Date();
});
}
/**
* 手指抬起时为 endTime 赋值当前时间
* 若 endTime 与 startTime 差值大于 700ms, 触发回调函数
*
* @private
* @param {function} callback 回调函数
*/
touchend(callback) {
this.el.addEventListener('touchend', function(event) {
// 清除默认行为
event.preventDefault();
// 记录手指抬起的时间戳
this.endTime = new Date();
// 判断手指按下和抬起的间隔时间是否大于 700 毫秒,大于则表示长按成功
if (this.endTime - this.startTime > 700) {
if (typeof callback === 'function') {
callback();
} else {
console.error('callback is not a function!');
}
}
});
}
}
win.LongPress = LongPress;
})(window);
改进方案
当然,这只是一种形式,它依赖于手指的状态:只有手指抬起才会触发回调函数。
那么我们能否再次改进呢?比如,手指不抬起,只要按住时间超过阈值,也能够触发回调函数?回答是肯定的,定时器如是说。
我们可以在手指按下时启动定时器,设置时间间隔,触发回调函数;手指抬起时,清除定时器。代码如下:
(function(win) {
/**
* 长按功能,长按 700ms 以上即可调用回调方法
*
* @class
*/
class LongPress {
/**
* 构造器
*
* @public
* @param {String} el 需要长按的 DOM 节点名
* @param {function} callback 长按触发的回调函数
*/
constructor(el, callback) {
this.el = document.querySelector(el);
this.timer = null;
this.init(callback);
}
/**
* 初始化
*
* @private
* @param {function} callback 回调函数
*/
init(callback) {
this.touchstart(callback);
this.touchend();
}
/**
* 手指按下时开启定时器,700 毫秒后触发回调函数
*
* @private
* @param {function} callback 回调函数
*/
touchstart(callback) {
this.el.addEventListener('touchstart', function(event) {
// 清除默认行为
event.preventDefault();
// 开启定时器
this.timer = setTimeout(() => {
if (typeof callback === 'function') {
callback();
} else {
console.error('callback is not a function!');
}
}, 700);
});
}
/**
* 手指抬起时清除定时器,无论按住时间是否达到 700 毫秒的阈值
*
* @private
*/
touchend() {
this.el.addEventListener('touchend', function(event) {
// 清除默认行为
event.preventDefault();
// 清除定时器
clearTimeout(this.timer);
});
}
}
win.LongPress = LongPress;
})(window);
避坑指南
目前发现有浏览器(如微信浏览器)在默认行为中添加了长按复制功能,而以上代码中却添加了 event.preventDefault()
清除默认行为,会屏蔽掉浏览器自带的长按功能,所以应视情况而定,取消清除默认行为的代码。