H5防误触按钮

237 阅读2分钟

前端开发中的防误触按钮的形式:滑动触发事件 长摁触发事件

滑动触发事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        width: 100vw;
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 50px;
      }
      .track {
        position: relative;
        width: 500px;
        height: 50px;
        line-height: 50px;
        text-align: center;
        background-color: #ccc;
        border-radius: 5px;
        overflow: hidden;
        font-size: 32px;
      }
      .progress {
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        background-color: skyblue;
      }
      .slider {
        position: absolute;
        top: 0;
        left: 0;
        width: 50px;
        height: 50px;
        background-color: lemonchiffon;
        cursor: pointer;
      }
      .act-info {
        position: absolute;
      }
    </style>
  </head>
  <body>
    <div class="track">
      <div class="progress"></div>
      <div class="slider"></div>
      <span class="act-info">拖动触发事件</span>
    </div>
    <script>
      const track = document.querySelector(".track");
      const slider = document.querySelector(".slider");
      const progress = document.querySelector(".progress");
      let isDragging = false;
      let startX, startLeft;
      let isComplete = false;

      // 记录初始位置
      const initialPosition = 0;

      // 触摸事件处理
      slider.addEventListener("touchstart", startDrag, { passive: false });
      document.addEventListener("touchmove", handleDrag, { passive: false });
      document.addEventListener("touchend", endDrag);

      // 鼠标事件处理
      slider.addEventListener("mousedown", startDrag);
      document.addEventListener("mousemove", handleDrag);
      document.addEventListener("mouseup", endDrag);

      function startDrag(e) {
        console.log("drag start");
        isDragging = true;
        slider.style.transition = "none";

        // 获取初始位置,兼容鼠标和触摸事件
        const clientX = e.type.includes("mouse")
          ? e.clientX
          : e.touches[0].clientX;
        startX = clientX;
        startLeft = slider.getBoundingClientRect().left;
        isComplete = false;

        // 阻止默认行为,防止页面滚动
        if (e.type.includes("touch")) {
          e.preventDefault();
        }
      }

      function handleDrag(e) {
        if (!isDragging) return;
        console.log("dragging");

        // 阻止默认行为,防止页面滚动
        if (e.type.includes("touch")) {
          e.preventDefault();
        }

        const wrapperRect = track.getBoundingClientRect();
        // 获取当前位置,兼容鼠标和触摸事件
        const clientX = e.type.includes("mouse")
          ? e.clientX
          : e.touches[0].clientX;

        const newX = Math.min(
          Math.max(clientX - startX + startLeft - wrapperRect.left, 0),
          wrapperRect.width - slider.offsetWidth
        );

        slider.style.left = `${newX}px`;
        progress.style.width = `${(newX / wrapperRect.width) * 100}%`;

        // 检查是否到达最右侧
        if (newX === wrapperRect.width - slider.offsetWidth) {
          isComplete = true;
          alert("Done");
        } else {
          isComplete = false;
        }
      }

      function endDrag() {
        console.log("drag end");
        if (!isDragging) return;
        isDragging = false;
        slider.style.transition = "left 0.2s ease";

        // 如果没有完成,重置位置
        if (!isComplete) {
          slider.style.left = `${initialPosition}px`;
          progress.style.width = "0%";
        }
      }
    </script>
  </body>
</html>

20250513154141_rec_.gif

长摁触发事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>逐渐拼凑的长方形进度条</title>
    <style>
      @import url("https://fonts.googleapis.com/css?family=Lato:700");

      * {
        box-sizing: border-box;
      }

      body {
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        background: #ecf0f1;
        font-family: "Lato", sans-serif;
      }

      .progress-btn-wrapper {
        width: 300px;
        height: 150px;
        position: relative;
      }

      .progress {
        width: 100%;
        height: 100%;
        border-radius: 5px;
        position: absolute;
        background: conic-gradient(
          #3498db 0deg,
          #3498db 0deg,
          transparent 0deg
        );
        transition: background 0.5s linear; /* Smooth transition */
      }

      .btn {
        position: absolute;
        width: 270px;
        height: 120px;
        border-radius: 5px;
        background: #34495e;
        top: 15px;
        left: 15px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-size: 2em;
      }

      .progress-text {
        font-size: 1.5em;
      }
    </style>
  </head>
  <body>
    <div class="progress-btn-wrapper">
      <div class="progress"></div>
      <div class="btn">
        <span class="progress-text">0%</span>
      </div>
    </div>

    <script>
      const progressText = document.querySelector(".progress-text");
      const progress = document.querySelector(".progress");
      const btn = document.querySelector(".btn");
      const duration = 2000;
      const step = 5;
      const interval = duration / (100 / step);
      let progressTimer = null;
      let percent = 0;

      // 按下时开始进度条
      btn.addEventListener("touchstart", (e) => {
        e.preventDefault();
        if (progressTimer) return; // 防止重复启动
        timer = setTimeout(() => {
          complete();
        }, duration);
        progressTimer = setInterval(() => {
          percent += step;
          if (percent > 100) percent = 100;
          updateProgress(percent);
        }, interval);
      });

      // 松开时平滑回退进度条
      btn.addEventListener("touchend", () => {
        clearInterval(progressTimer);
        progressTimer = null;

        // 如果进度条不是 100%,平滑回退
        if (percent < 100) {
          smoothRevert();
        }
      });

      // 更新进度条和进度文本
      function updateProgress(percent) {
        const degrees = (percent / 100) * 360;
        progress.style.background = `conic-gradient(#3498db 0deg, #3498db ${degrees}deg, transparent ${degrees}deg)`;
        progressText.textContent = `${percent}%`;
      }

      // 平滑回退进度条
      function smoothRevert() {
        const revertInterval = 10; // 回退动画间隔
        const revertStep = 1; // 回退步长
        clearTimeout(timer);
        const revertTimer = setInterval(() => {
          percent -= revertStep;
          if (percent <= 0) {
            clearInterval(revertTimer);
            percent = 0;
            updateProgress(percent);
          } else {
            updateProgress(percent);
          }
        }, revertInterval);
      }

      // 完成后的处理逻辑
      function complete() {
        console.log("开始执行业务逻辑");
      }
    </script>
  </body>
</html>

20250513184614_rec_.gif

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Touch Progress Example</title>
    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
      }
      #container {
        width: 200px;
        height: 88px;
        border: 1px solid black;
        position: relative;
      }
      #progress {
        width: 0%;
        height: 100%;
        background-color: skyblue;
        transition: width 1s linear;
        position: absolute;
        z-index: 2;
      }
      #text {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 3;
      }
    </style>
  </head>
  <body>
    <div id="container">
      <div id="text">Long Press</div>
      <div id="progress"></div>
    </div>
    <script>
      // 获取元素
      const container = document.getElementById("container");
      const pickupProgress = document.getElementById("progress");
      const text = document.getElementById("text");
      let touchEventTimer = null;
      //这个事件负责
      const handleTouchStart = (e) => {
        e.preventDefault();
        pickupProgress.style.width = "100%";
        touchEventTimer = setTimeout(() => {
          console.log("开始执行touch完成后的事件逻辑");
          touchEventTimer = null;
        }, 1000);
        console.log("touch开始", touchEventTimer);
      };

      const handleTouchEnd = () => {
        console.log("touch结束");
        //未touch 1s 终止计时的任务
        if (touchEventTimer) {
          pickupProgress.style.width = "0%";
          clearTimeout(touchEventTimer);
          touchEventTimer = null;
        } else {
          text.innerText = "Finished";
          pickupProgress.style.background = "pink";
        }
      };
      if (container) {
        container.addEventListener("touchstart", handleTouchStart, {
          passive: false,
        });
        container.addEventListener("touchend", handleTouchEnd, {
          passive: false,
        });
      }
    </script>
  </body>
</html>

20250613144059_rec_.gif