由于业务需要一个滑块验证,不同于市面上的数字验证和图形验证,滑块验证不需要太动脑,所以实现一个组件帮助大家开发

一、组件介绍

在现代Web应用中,滑块验证是一种常用的交互式验证码方式,既能防止恶意提交,又不影响用户体验。这里将介绍一个基于Vue3组合式API实现的滑块验证组件,包括设计思路、核心代码、使用方法、参数配置、演示示例和扩展方向。

二、设计思路

  1. 设计目标

    • 创建一个可高度自定义的滑块验证组件。
    • 支持动态渲染、拖动进度背景实时跟随。
    • 验证完成后触发成功回调,否则复位。
  2. 实现逻辑

    • 鼠标按下时记录起始位置,监听mousemove更新滑块位置和进度条宽度。
    • 松开鼠标或离开容器边界时,根据滑块位置决定验证是否成功。
  3. 状态控制

    • blockState:0(未开始)、1(拖动中)、2(完成)。
    • leftP:滑块当前位置(像素)。
    • GreenLeftP:进度背景宽度。

三、组件核心代码

<template>
  <div
    ref="sliderContainer"
    @mousemove="onMouseMove"
    @mouseup="onMouseUp"
    class="slider-verify-container"
    @mouseleave="onMouseLeave"
    :style="containerStyle"
  >
    <span v-if="blockState === 0" :style="hintTextStyle" class="hint-text">{{ hintText }}</span>

    <div
      @mousedown="onMouseDown"
      :style="{ left: leftP, ...sliderBlockStyle }"
      class="slider-verify-block"
    >{{ sliderIcon }}</div>

    <div
      :style="{ width: GreenLeftP, ...completeStyle }"
      class="slider-verify-complete"
    >
      <span v-if="blockState === 2" :style="successTextStyle" class="success-text">{{ successText }}</span>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const props = defineProps({
  width: { type: [String, Number], default: '100%' },
  height: { type: [String, Number], default: '40px' },
  sliderSize: { type: [String, Number], default: '40px' },
  hintText: { type: String, default: '请按住滑块,拖动到最右边' },
  successText: { type: String, default: '验证成功' },
  sliderIcon: { type: String, default: '››' },
  sliderColor: { type: String, default: '#ffffff' },
  completeColor: { type: String, default: '#2ed573' },
  textColor: { type: String, default: '#666666' },
  successTextColor: { type: String, default: '#ffffff' },
  disabled: { type: Boolean, default: false },
})

const emit = defineEmits(['success', 'failed'])

const leftP = ref('0')
const GreenLeftP = ref('0')
const blockState = ref(0)
const startP = ref(undefined)
const sliderContainer = ref(null)

const containerStyle = computed(() => ({
  width: typeof props.width === 'number' ? `${props.width}px` : props.width,
  height: typeof props.height === 'number' ? `${props.height}px` : props.height,
  color: props.textColor,
}))

const sliderBlockStyle = computed(() => ({
  width: typeof props.sliderSize === 'number' ? `${props.sliderSize}px` : props.sliderSize,
  height: typeof props.sliderSize === 'number' ? `${props.sliderSize}px` : props.sliderSize,
  backgroundColor: props.sliderColor,
  cursor: props.disabled ? 'not-allowed' : 'grab',
}))

const completeStyle = computed(() => ({
  backgroundColor: props.completeColor,
  height: typeof props.height === 'number' ? `${props.height}px` : props.height,
}))

const hintTextStyle = computed(() => ({ color: props.textColor }))
const successTextStyle = computed(() => ({ color: props.successTextColor }))

const onMouseDown = (e) => {
  if (props.disabled) return
  if (blockState.value !== 2) {
    leftP.value = '0'
    blockState.value = 1
    startP.value = { clientX: e.clientX }
  } else {
    leftP.value = '0'
    blockState.value = 0
  }
}

const onMouseMove = (e) => {
  if (props.disabled || blockState.value !== 1) return
  const containerWidth = sliderContainer.value.offsetWidth
  const sliderWidth = parseInt(props.sliderSize, 10)
  let width = e.clientX - startP.value.clientX
  if (width + sliderWidth >= containerWidth) {
    leftP.value = `${containerWidth - sliderWidth}px`
    GreenLeftP.value = `${containerWidth}px`
    blockState.value = 2
    emit('success')
  } else {
    leftP.value = `${width}px`
    GreenLeftP.value = `${width + sliderWidth}px`
  }
}

const onMouseUp = () => {
  if (props.disabled || blockState.value === 2) return
  leftP.value = '0'
  GreenLeftP.value = '0'
  blockState.value = 0
  emit('failed')
}

const onMouseLeave = () => {
  if (props.disabled || blockState.value === 2) return
  leftP.value = '0'
  GreenLeftP.value = '0'
  blockState.value = 0
  emit('failed')
}
</script>

<style lang="scss" scoped>
.slider-verify-container {
  background-color: transparent;
  position: relative;
  box-shadow: 0 0 0 1px #dcdfe6 inset;
  text-align: center;
  line-height: 40px;
  border-radius: 4px;
  margin: 20px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  user-select: none;
}

.slider-verify-complete {
  width: 0;
  border-radius: 4px;
  position: absolute;
  left: 0;
  top: 0;
}

.slider-verify-block {
  position: absolute;
  left: 0;
  top: 0;
  box-shadow: 0 0 0 1px #dcdfe6 inset;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  z-index: 15;
}

.success-text,
.hint-text {
  font-size: 13px;
}
</style>

四、演示截图

滑块验证组件成功效果


滑块验证组件未滑动效果

五、如何使用?

上面的代码就是组件,定义好组件以后,在您想插入的地方调用该VUE组件就可以

<template>
  <SliderVerify
    width="100%"
    height="50px"
    slider-size="50px"
    hint-text="请按住滑块并拖动完成验证"
    success-text="验证通过!"
    slider-icon=">>>"
    slider-color="#409EFF"
    complete-color="#67C23A"
    text-color="#606266"
    success-text-color="#fff"
    @success="onSuccess"
    @failed="onFail"
  />
</template>

<script setup>
import SliderVerify from '@/components/SliderVerify.vue'
const onSuccess = () => console.log('验证成功')
const onFail = () => console.log('验证失败')
</script>

六、API参数说明

参数名称类型默认值说明
widthString/Number100%容器宽度
heightString/Number40px容器高度
sliderSizeString/Number40px滑块尺寸
hintTextString请按住滑块,拖动到最右边初始提示文字
successTextString验证成功成功提示文字
sliderIconString››滑块内文字或图标
sliderColorString#ffffff滑块颜色
completeColorString#2ed573背景进度条颜色
textColorString#666666提示文字颜色
successTextColorString#ffffff成功提示文字颜色
disabledBooleanfalse是否禁用组件

七、事件回调

事件名称参数说明
success验证完成时触发
failed验证失败或未完成时触发

八、扩展思路

  • 支持touch事件,适配移动端。
  • 引入偏移,提高安全性。
  • 组件方法扩展:增加手动reset方法。
  • 与表单库结合,成为校验前置组件。

九、总结

这个Vue滑块验证组件在代码简洁性、用户交互体验、扩展能力方面都具备良好基础,适用于多种前端验证场景。
如果您有更好的组件也可以评论分享一下哈!我没找到只能自己上手+AI协助了

最后修改:2025 年 03 月 25 日 10 : 00 AM
如果觉得此文章有用,请随意打赏