vue3实现滑块验证

本文根据插件vue-drag-verify修改后实现。

插件本身不支持vue3中使用npm i 的方式引入,如果直接引入的话会报错,所以需要在gitlab(GitHub - w3cpress/vue-drag-verify: vue滑块验证组件,图片验证组件,图片旋转验证组件)根据需要下载对应的文件(要翻墙才能下载哦)然后放在components中当普通的组件引入即可

本次开发下载的是dragVerify.vue文件,但由于vue-drag-verify传参的方式是.sync,vue3已经不再使用这个方法,所以对组件进行了调整:

<template>
  <div
    ref="dragVerify"
    class="drag_verify"
    :style="dragVerifyStyle"
    @mousemove="dragMoving"
    @mouseup="dragFinish"
    @mouseleave="dragFinish"
    @touchmove="dragMoving"
    @touchend="dragFinish"
  >

    <div
      class="dv_progress_bar"
      :class="{goFirst2:isOk}"
      ref="progressBar"
      :style="progressBarStyle"
    >

    </div>
    <div
      class="dv_text"
      :style="textStyle"
      ref="messageRef"
    >
      <slot
        name="textBefore"
        v-if="$slots.textBefore"
      ></slot>
      {{message}}
      <slot
        name="textAfter"
        v-if="$slots.textAfter"
      ></slot>
    </div>

    <div
      class="dv_handler dv_handler_bg"
      :class="{goFirst:isOk}"
      @mousedown="dragStart"
      @touchstart="dragStart"
      ref="handler"
      :style="handlerStyle"
    >
      <IconFont :type="value ? successIcon : handlerIcon"/>
    </div>

  </div>
</template>
<script setup lang="ts">
import { ref, reactive, toRefs, onMounted, computed } from 'vue'
import { MouseEvent } from '@vue/runtime-dom'
const emit = defineEmits(['handlerMove', 'update:value', 'passCallback'])
interface PropsType {
  value: boolean
  width?: number
  height?: number
  text?: string
  successText?: string
  background?: string
  progressBarBg?: string
  completedBg?: string
  circle?: boolean
  radius?: string
  handlerIcon?: string
  successIcon?: string
  handlerBg?: string
  textSize?: string
  textColor?: string
}
const props = withDefaults(defineProps<PropsType>(), {
  value: false,
  width: 250,
  height: 40,
  text: "swiping to the right side",
  successText: 'success',
  background: '#eee',
  progressBarBg: '#134bec',
  completedBg: '#134bec',
  circle: false,
  radius: '4px',
  handlerIcon: 'icongengduo',
  successIcon: 'iconxiala-yuan',
  handlerBg: '#fff',
  textSize: '14px',
  textColor: '#333',
})
interface stateType {
  isMoving: boolean
  x: number
  isOk: boolean
}
const state = reactive(<stateType>{
  isMoving: false,
  x: 0,
  isOk: false
})
const { isMoving, x, isOk } = toRefs(state)
const dragVerify = ref()
const messageRef = ref()
const handler = ref()
const progressBar = ref()
onMounted(() => {
  dragVerify.value?.style.setProperty("--textColor", props.textColor);
  dragVerify.value?.style.setProperty("--width", Math.floor(props.width / 2) + "px");
  dragVerify.value?.style.setProperty("--pwidth", -Math.floor(props.width / 2) + "px");
})
const handlerStyle = {
  left: "0",
  width: props.height + "px",
  height: props.height + "px",
  background: props.handlerBg
}
const dragVerifyStyle = {
  width: props.width + "px",
  height: props.height + "px",
  lineHeight: props.height + "px",
  background: props.background,
  borderRadius: props.circle ? props.height / 2 + "px" : props.radius
}
const progressBarStyle = {
  background: props.progressBarBg,
  height: props.height + "px",
  borderRadius: props.circle
    ? props.height / 2 + "px 0 0 " + props.height / 2 + "px"
    : props.radius
}
const textStyle = {
  height: props.height + "px",
  width: props.width + "px",
  fontSize: props.textSize
}
const message = computed(() => {
  return props.value ? props.successText : props.text
})

const dragStart = (e: MouseEvent) => {
  console.log(!props.value, 'dragStart')
  if (!props.value) {
    state.isMoving = true
    handler.value.style.transition = 'none'
    state.x =
      (e.pageX || e.touches[0].pageX) -
      parseInt(handler.value.style.left.replace("px", ""), 10)
  }
  emit("handlerMove")
}
const dragMoving = (e: MouseEvent) => {
  if (state.isMoving && !props.value) {
    var _x = (e.pageX || e.touches[0].pageX) - state.x;
    if (_x > 0 && _x <= props.width - props.height) {
      handler.value.style.left = _x + "px";
      progressBar.value.style.width = _x + props.height / 2 + "px";
    } else if (_x > props.width - props.height) {
      handler.value.style.left = props.width - props.height + "px";
      progressBar.value.style.width = props.width - props.height / 2 + "px";
      passVerify()
    }
  }
}
const dragFinish = (e: MouseEvent) => {
  if (state.isMoving && !props.value) {
    var _x = (e.pageX || e.changedTouches[0].pageX) - state.x;
    if (_x < props.width - props.height) {
      state.isOk = true
      handler.value.style.left = "0";
      handler.value.style.transition = 'all 0.2s'
      progressBar.value.style.width = "0"
      state.isOk = false
    } else {
      handler.value.style.transition = 'none'
      handler.value.style.left = props.width - props.height + "px";
      progressBar.value.style.width = props.width - props.height / 2 + "px";
      passVerify()
    }
    state.isMoving = false
  }
}
const passVerify = () => {
  emit("update:value", true)
  state.isMoving = false;
  progressBar.value.style.background = props.completedBg
  messageRef.value.style["-webkit-text-fill-color"] = "unset";
  messageRef.value.style.animation = "slidetounlock2 3s infinite";
  messageRef.value.style.color = "#fff";
  emit("passCallback");
}
const reset = () => {
  handler.value.style.left = "0"
  progressBar.value.valueFormat.style.width = "0"
  handler.value.children[0].type = props.handlerIcon
  messageRef.value.style["-webkit-text-fill-color"] = "transparent"
  messageRef.value.style.animation = "slidetounlock 3s infinite"
  messageRef.value.style.color = props.background
}
defineExpose({
  reset
})
</script>
<style scoped>
.drag_verify {
  position: relative;
  background-color: #e8e8e8;
  text-align: center;
  overflow: hidden;
}
.drag_verify .dv_handler {
  position: absolute;
  top: 0px;
  left: 0px;
  cursor: move;
}
.drag_verify .dv_handler i {
  color: #666;
  padding-left: 0;
  font-size: 16px;
}
.drag_verify .dv_handler .el-icon-circle-check {
  color: #6c6;
  margin-top: 9px;
}
.drag_verify .dv_progress_bar {
  position: absolute;
  height: 34px;
  width: 0px;
}
.drag_verify .dv_text {
  position: absolute;
  top: 0px;
  color: transparent;
  -moz-user-select: none;
  -webkit-user-select: none;
  user-select: none;
  -o-user-select: none;
  -ms-user-select: none;
  background: -webkit-gradient(
    linear,
    left top,
    right top,
    color-stop(0, var(--textColor)),
    color-stop(0.4, var(--textColor)),
    color-stop(0.5, #fff),
    color-stop(0.6, var(--textColor)),
    color-stop(1, var(--textColor))
  );
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  -webkit-text-size-adjust: none;
  animation: slidetounlock 3s infinite;
}
.drag_verify .dv_text * {
  -webkit-text-fill-color: var(--textColor);
}
.goFirst {
  left: 0px !important;
  transition: left 0.5s;
}
.goFirst2 {
  width: 0px !important;
  transition: width 0.5s;
}
</style>
<style>
@-webkit-keyframes slidetounlock {
  0% {
    background-position: var(--pwidth) 0;
  }
  100% {
    background-position: var(--width) 0;
  }
}
@-webkit-keyframes slidetounlock2 {
  0% {
    background-position: var(--pwidth) 0;
  }
  100% {
    background-position: var(--pwidth) 0;
  }
}
</style>

使用方式为:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值