<template>
  <!-- 滑动验证码容器 -->
  <div class="slider-container" ref="containerRef">
    <!-- 滑动遮罩层，显示滑动进度 -->
    <div class="slider-mask" :style="{ width: sliderMaskWidth }" />
    <!-- 滑块按钮 -->
    <div
      class="slider"
      ref="sliderRef"
      @mousedown="handleDragStart"
      :class="{ 'slider-success': verified }"
      :style="{ left: sliderLeft }"
    >
      <!-- 滑块图标 -->
      <Icon icon="ant-design:double-right-outlined" :size="20" />
    </div>
    <!-- 提示文本 -->
    <div class="slider-text" :class="{ 'slider-text-success': verified }">
      {{ verified ? "验证通过" : "将滑块拖动至右侧完成验证" }}
    </div>
  </div>
</template>
 
<script setup lang="ts">
import { ref, defineEmits, onUnmounted } from "vue"
 
const emit = defineEmits(["verifySuccess"])
 
// DOM 引用
const containerRef = ref<HTMLElement | null>(null) // 容器元素引用
const sliderRef = ref<HTMLElement | null>(null) // 滑块元素引用
 
// 状态变量
const sliderLeft = ref("0px") // 滑块左侧位置
const sliderMaskWidth = ref("0px") // 遮罩层宽度
const verified = ref(false) // 验证状态
 
// 拖动相关变量
let startX = 0 // 开始拖动时的 X 坐标
let sliderLeft_temp = 0 // 临时存储滑块位置
 
/**
 * 开始拖动处理
 * @param e 鼠标事件对象
 */
const handleDragStart = (e: MouseEvent) => {
  if (verified.value) return // 如果已验证通过，不再处理
  startX = e.clientX
  sliderLeft_temp = parseInt(sliderLeft.value)
  // 添加鼠标移动和松开事件监听
  document.addEventListener("mousemove", handleDragMove)
  document.addEventListener("mouseup", handleDragEnd)
}
 
/**
 * 拖动过程处理
 * @param e 鼠标事件对象
 */
const handleDragMove = (e: MouseEvent) => {
  if (verified.value) return
  const container = containerRef.value
  if (!container) return
 
  // 计算拖动距离
  const diff = e.clientX - startX
  const containerWidth = container.offsetWidth
  const sliderWidth = sliderRef.value?.offsetWidth || 0
  const maxLeft = containerWidth - sliderWidth
 
  // 计算新位置并限制范围
  let newLeft = sliderLeft_temp + diff
  if (newLeft < 0) newLeft = 0
  if (newLeft > maxLeft) newLeft = maxLeft
 
  // 更新滑块和遮罩层位置
  sliderLeft.value = newLeft + "px"
  sliderMaskWidth.value = newLeft + sliderWidth / 2 + "px"
 
  // 检查是否验证成功
  if (newLeft === maxLeft) {
    verified.value = true
    emit("verifySuccess", true) // 触发验证成功
    handleDragEnd()
  }
}
 
/**
 * 结束拖动处理
 */
const handleDragEnd = () => {
  if (!verified.value) {
    // 如果未验证成功，重置位置
    sliderLeft.value = "0px"
    sliderMaskWidth.value = "0px"
  }
  // 移除事件监听
  document.removeEventListener("mousemove", handleDragMove)
  document.removeEventListener("mouseup", handleDragEnd)
}
 
// 组件卸载时清理事件监听
onUnmounted(() => {
  document.removeEventListener("mousemove", handleDragMove)
  document.removeEventListener("mouseup", handleDragEnd)
})
</script>
 
<style scoped>
/* 滑动验证码容器样式 */
.slider-container {
  position: relative;
  width: 100%;
  height: 42px;
  background-color: #f5f5f5;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  margin-top: 20px;
}
 
/* 滑动遮罩层样式 */
.slider-mask {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background-color: #d1e9fc;
  border-radius: 8px;
  transition: width 0.1s linear;
}
 
/* 滑块按钮样式 */
.slider {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 60px;
  height: 42px;
  background: #e1dede;
  border-radius: 8px;
  cursor: pointer;
  transition: background-color 0.2s;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}
 
/* 验证成功时滑块样式 */
.slider-success {
  background-color: #1ea0fa;
}
 
/* 提示文本样式 */
.slider-text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  user-select: none;
  font-weight: 400;
  font-size: 12px;
  color: #9cb3c5;
  width: auto;
}
 
/* 验证成功时文本样式 */
.slider-text-success {
  color: #1ea0fa;
}
</style>