一键三连在Web端和移动端的实现

1,660 阅读3分钟

最近看不少B站UP主在视频开始or结束都会请求观众来个一键三连,具体操作就是用户长按点赞按钮,一段时间后会触发某个事件,一次性完成点赞、投币和收藏操作。下面将从前端工程师的角度,来分析一下这个过程,并给出我的实现方式~

首先来说,实现一键三连需要同时满足两个必要条件,一是「点击」点赞按钮,二是需要长按。上面的「点击」我用引号进行了标记,是因为用户感知的「点击」行为是比较抽象的,而在前端工程师眼里触发click事件会经历一个有序触发相关事件的过程。

首先在PC端,前端工程师眼里触发click事件会先依次触发mousedownmouseup事件。而在移动端,触发click事件会先依次触发touchstarttouchend事件。

根据click事件规范,我们知道在PC端鼠标按下任意键并释放该键之后会触发click,「按下」和「释放」对应mousedownmouseup事件。移动端因为页面滚动等操作需要手指触摸屏幕来完成,因此触发click事件之前,会先依次触发touchstarttouchend事件。基于上述理解可知mouseup/touchend事件和click事件之间的时间间隔很小,要实现「长按」操作,最优选择是在mousedown/touchstartmouseup/touchend事件之间执行相关操作。下面将实现一种一键三连的效果

需求

长按3秒点赞,一键三连;长按时间少于1s则视为仅点赞;长按时间在1s至3s之间,视为一键三连失败,不做任何操作。

实现方案

  1. mousedown/touchstart事件触发时,记录触发时间,同时通过setTimeout设置定时器

  2. mouseup/touchend事件触发时,计算当前时间和mousedown/touchstart事件触发时的时间差,根据时间差决定进一步操作。

具体实现如下:

//html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <meta name="viewport" content="user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #clickBtn {
            width: 60px;
            height: 40px;
            background: red;
        }
</style>
</head>

<body>
    <div id="clickBtn"></div>
    <p id="timeText"></p>
</body>

</html>
//点赞、一键三连方法
function like(){
  console.log("点赞");
}

function longPress(){
  console.log("一键三连");
}

function getTime() {
  const now = new Date().getTime();
  timeText.innerText = (now - start) / 1000;
}

PC端实现方式:

let timer, startTime, setTimeText;
let start = new Date().getTime();

const clickBtn = document.getElementById("clickBtn");
const timeText = document.getElementById("timeText");

timeText.innerText = "";

clickBtn.addEventListener("mousedown",function(){
  startTime = new Date().getTime();//获取mousedown触发时间
  setTimeText = setInterval(getTime, 100);
  timer = setTimeout(longPress, 3000);//设置定时器
});

clickBtn.addEventListener("mouseup",function(){
  const now = new Date().getTime(); //获取mouseup触发时间
  clearInterval(setTimeText);
  if (now - startTime < 1000) { //点按仅触发点赞
      like();
      clearTimeout(timer);
  } else if (now - startTime < 3000) { //长按时间不足,不触发任何操作
      clearTimeout(timer);
  }
});

移动端实现只需要将对应事件替换为touchstarttouchend即可~