由于业务需要一个滑块验证,不同于市面上的数字验证和图形验证,滑块验证不需要太动脑,所以实现一个组件帮助大家开发
一、组件介绍
在现代Web应用中,滑块验证是一种常用的交互式验证码方式,既能防止恶意提交,又不影响用户体验。这里将介绍一个基于Vue3组合式API实现的滑块验证组件,包括设计思路、核心代码、使用方法、参数配置、演示示例和扩展方向。
二、设计思路
设计目标
- 创建一个可高度自定义的滑块验证组件。
- 支持动态渲染、拖动进度背景实时跟随。
- 验证完成后触发成功回调,否则复位。
实现逻辑
- 鼠标按下时记录起始位置,监听
mousemove
更新滑块位置和进度条宽度。 - 松开鼠标或离开容器边界时,根据滑块位置决定验证是否成功。
- 鼠标按下时记录起始位置,监听
状态控制
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参数说明
参数名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
width | String/Number | 100% | 容器宽度 |
height | String/Number | 40px | 容器高度 |
sliderSize | String/Number | 40px | 滑块尺寸 |
hintText | String | 请按住滑块,拖动到最右边 | 初始提示文字 |
successText | String | 验证成功 | 成功提示文字 |
sliderIcon | String | ›› | 滑块内文字或图标 |
sliderColor | String | #ffffff | 滑块颜色 |
completeColor | String | #2ed573 | 背景进度条颜色 |
textColor | String | #666666 | 提示文字颜色 |
successTextColor | String | #ffffff | 成功提示文字颜色 |
disabled | Boolean | false | 是否禁用组件 |
七、事件回调
事件名称 | 参数 | 说明 |
---|---|---|
success | 无 | 验证完成时触发 |
failed | 无 | 验证失败或未完成时触发 |
八、扩展思路
- 支持
touch
事件,适配移动端。 - 引入偏移,提高安全性。
- 组件方法扩展:增加手动
reset
方法。 - 与表单库结合,成为校验前置组件。
九、总结
这个Vue滑块验证组件在代码简洁性、用户交互体验、扩展能力方面都具备良好基础,适用于多种前端验证场景。
如果您有更好的组件也可以评论分享一下哈!我没找到只能自己上手+AI协助了
版权属于:不冷
本文链接:https://www.buleng.xyz/archives/242/
转载时须注明出处及本声明