vue3.2+ 滑动验证组件,pc/手机通用,即插即用
一、前言
vue已经更新到3.2+,使用了script的setup属性语法,支持typescript,但是网上已有的大部分滑动验证组件都是旧版本,还不支持触摸,所以决定写一个:
- 支持vue3.2+语法
- 支持typescript
- 支持pc/手机(自动适配)
- 即插即用
的滑动验证组件,方便大家。当然,这个只是静态的校验,如果需要动态校验,需要和后端配合。
二、成果展示
三、组件使用
import组件,然后 <dragVerify v-model:value="form.isVerifyPass"></dragVerify> 使用即可,其中v-model:value 为双向绑定结果 支持属性:
- successIcon 成功图标{string} 默认值 ‘iconfont icon-status-nor’
- successText 成功文字string} 默认值 ‘验证成功’
- startIcon 开始的图标{string} 默认值 ‘iconfont icon-login-slid’
- startText 开始的文字{string} 默认值 ‘拖动滑块到最右边’
<template>
<div class="test">
<h3>vue3.2+ 滑动验证组件,pc/手机通用</h3>
<div class="content">
<dragVerify v-model:value="form.isVerifyPass"></dragVerify>
</div>
<div>校验结果:{{ form.isVerifyPass }}</div>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import dragVerify from '@/components/dragVerify.vue'
const form = reactive({
isVerifyPass: false,
})
</script>
四、vue3.2+ 滑动验证组件 源码
<template>
<div class="drag-verify">
<div class="range" :class="verifyResult ? 'success' : ''">
<div class="block" @mousedown="onStart" @touchstart="onStart">
<i :class="verifyResult ? successIcon : startIcon"></i>
</div>
<span class="text">{{ verifyResult ? successText : startText }}</span>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const emit = defineEmits(['update:value'])
defineProps({
value: {
type: Boolean,
defalut: false,
},
successIcon: {
type: String,
default: 'iconfont icon-status-nor',
},
successText: {
type: String,
default: '验证成功',
},
startIcon: {
type: String,
default: 'iconfont icon-login-slid',
},
startText: {
type: String,
default: '拖动滑块到最右边',
},
})
const verifyResult = ref(false)
const isTouch = 'ontouchstart' in document.documentElement
const moveEvent = isTouch ? 'touchmove' : 'mousemove'
const upEvent = isTouch ? 'touchend' : 'mouseup'
const onStart = (ev: MouseEvent | TouchEvent) => {
let disX = 0
const iconWidth = 40
const ele = document.querySelector('.drag-verify .block') as HTMLElement
const startX = (ev as MouseEvent).clientX || (ev as TouchEvent).touches[0].pageX
const parentWidth = ele.offsetWidth
const MaxX = parentWidth - iconWidth
if (verifyResult.value) {
return false
}
const onMove = (e: MouseEvent | TouchEvent) => {
const endX = (e as MouseEvent).clientX || (e as TouchEvent).touches[0].pageX
disX = endX - startX
if (disX <= 0) {
disX = 0
}
if (disX >= MaxX - iconWidth) {
disX = MaxX
}
ele.style.transition = '.1s all'
ele.style.transform = `translateX(${disX}px)`
}
const onEnd = () => {
if (disX !== MaxX) {
ele.style.transition = '.5s all'
ele.style.transform = 'translateX(0)'
} else {
verifyResult.value = true
emit('update:value', verifyResult.value)
}
document.removeEventListener(moveEvent, onMove)
document.removeEventListener(upEvent, onEnd)
}
document.addEventListener(moveEvent, onMove)
document.addEventListener(upEvent, onEnd)
}
</script>
<style lang="scss" scoped>
$color-primary: #03c5e5;
@mixin flex {
display: flex;
justify-content: center;
align-items: center;
}
.drag-verify {
width: 100%;
.range {
background-color: #ececee;
position: relative;
border-radius: 4px;
transition: 1s all;
user-select: none;
color: #666;
overflow: hidden;
@include flex;
height: 40px;
&.success {
background-color: $color-primary;
color: #fff;
.text {
position: relative;
z-index: 1;
}
.block i {
color: $color-primary;
}
}
.block {
display: block;
position: absolute;
left: calc(-100% + 40px);
width: 100%;
height: 100%;
background: $color-primary;
border-radius: 4px;
overflow: hidden;
i {
position: absolute;
right: 0;
width: 40px;
height: 100%;
font-size: 20px;
color: #c8c9cc;
background-color: #fff;
border: 1px solid #e5e5e5;
border-radius: 4px;
cursor: pointer;
@include flex;
}
}
}
}
</style>
五、最后,点个赞
如果帮到你,点个赞再走 !
|