效果如下:
vue3 滑块验证演示
<template>
<div class="slider-verification" ref="sliderContainer">
<div class="slider-left-bg" :style="sliderLeftWidthStyle"></div>
<div class="prompt-text" :style="verifySuccess ? promptTextStyleSuccess: {}">
{
{ verifySuccess ? '验证通过' : '向右拖动滑块进行验证' }}
</div>
<div ref="slider" @mousedown="mouseDownHandler($event)" :class="{'slider-verify-success':verifySuccess}"
class="slider" :style="sliderToLeftStyle">
<el-icon v-if="verifySuccess" :size="iconSize" color="#fff">
<CircleCheck />
</el-icon>
<el-icon v-else :size="iconSize" color="#fff">
<DArrowRight />
</el-icon>
</div>
</div>
</template>
<script setup lang="ts">
interface Props {
multiple: number,
promptTextStyleSuccess: Record<any, any>
}
interface Emits {
(e: 'statusChange', val: boolean): void
}
const props = withDefaults(defineProps<Props>(), {
multiple: 2,
promptTextStyleSuccess: () => ({
color: '#ffffff'
})
})
const emits = defineEmits<Emits>()
let sliderState = ref(false)
let verifySuccess = ref(false)
let beginClientX = ref(0)
let maxWidth = ref(0)
const iconSize = ref(22)
const slideWidth = ref(0)
//鼠标移动
const mouseMoveHandler = (e) => {
if (sliderState.value) {
let width = (e.clientX - beginClientX.value) / props.multiple;
if (width > 0 && width <= maxWidth.value) {
slideWidth.value = width
} else if (width > maxWidth.value) {
slideWidth.value = maxWidth.value
verifySuccessFun();
}
}
}
//鼠标松开
const mouseUpHandler = (e) => {
sliderState.value = false;
let width = (e.clientX - beginClientX.value) / props.multiple;
if (width < maxWidth.value) {
slideWidth.value = 0
}
}
//验证通过
const verifySuccessFun = () => {
verifySuccess.value = true
emits('statusChange', true)
document.getElementsByTagName('html')[0].removeEventListener('mousemove', mouseMoveHandler);
document.getElementsByTagName('html')[0].removeEventListener('mouseup', mouseUpHandler);
slideWidth.value = maxWidth.value
}
const slider = ref(null)
const sliderContainer = ref(null)
//事件监听
const addListener = () => {
document.getElementsByTagName('html')[0].addEventListener('mousemove', mouseMoveHandler);
document.getElementsByTagName('html')[0].addEventListener('mouseup', mouseUpHandler)
}
// 重置
const reset = () => {
addListener()
emits('statusChange', false)
beginClientX.value = 0
sliderState.value = false
verifySuccess.value = false
slideWidth.value = 0
}
// 鼠标在滑块上按下事件
const mouseDownHandler = (e) => {
if (!verifySuccess.value) {
sliderState.value = true;
beginClientX.value = e.clientX;
}
}
onMounted(() => {
maxWidth.value = sliderContainer.value.offsetWidth - slider.value.offsetWidth;
addListener()
})
const sliderToLeftStyle = computed(() => ({ left: slideWidth.value + 'px' }))
const sliderLeftWidthStyle = computed(() => ({ width: slideWidth.value + 'px' }))
defineExpose({
reset
})
</script>
.slider-verification {
position: relative;
background-color: var(--ep-color-primary);
width: 100%;
height: 100%;
line-height: 48px;
text-align: center;
user-select: none;
}
.slider {
position: absolute;
top: 0;
width: 42px;
height: 48px;
cursor: move;
background: var(--ep-color-primary-light-5);
background-size: 30px 30px;
display: flex;
align-items: center;
justify-content: center;
}
.slider-verify-success {
background: var(--ep-color-primary-light-5);
background-size: 30px 30px;
}
//滑块滑过区域的样式
.slider-left-bg {
// background-color: rgba(0, 235, 255, 0.42);
background: rgba(0, 235, 255, 0.3);
width: 0;
height: 100%;
}
//提示文本样式
.prompt-text {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 48px;
text-align: center;
font-size: 14px;
line-height: 48px;
color: #ffffff;
}