vant+vue3+ts 的滑块验证

2 篇文章 1 订阅

vant+vue3+ts 的滑块验证

效果图
在这里插入图片描述

<template>
  <div ref="stage" class="stage">
    <div id="slider" ref="slider" class="slider">
      <div class="label">向右滑动验证</div>
      <div id="track" ref="track" class="track">
        <div id="bg-green" class="bg-green"></div>
      </div>
      <div
        id="btn"
        ref="btn"
        class="button"
        @touchend="touchend"
        @touchmove="touchmove"
        @touchstart="touchstart"
      >
        <div id="icon" class="icon">
          <van-icon v-if="data.isSuccess === state[2]" color="#07c160" name="passed" />
          <van-icon v-else-if="data.isSuccess === state[0]" name="arrow" />
          <van-icon v-else name="close" color="#ee0a24" />
        </div>
        <div id="spinner" class="spinner"></div>
      </div>
    </div>
  </div>
</template>
 type dataInterface = {
    oW: number
    oLeft: number
    isMove: boolean
    isSuccess: string
  }
  const state: Array<string> = ['wait', 'error', 'success']
  const data = reactive<dataInterface>({
    isMove: true,
    oW: 0,
    oLeft: 0,
    isSuccess: state[0],
  })
  const btn = ref<any>({})
  const track = ref<any>({})
  const slider = ref<any>({})
  const stage = ref<any>({})
  const touchstart = (e: TouchEvent) => {
    if (!data.isMove) return
    data.isSuccess = state[0]
    const touches = e.changedTouches[0]
    data.oW = touches.clientX - btn.value?.offsetLeft
    btn.value.className = 'button'
    track.value.className = 'track'
  }
  const touchmove = (e: TouchEvent) => {
    const touches = e.touches[0]
    if (data.isMove) {
      data.oLeft = touches.clientX - data.oW
      if (data.oLeft < 0) {
        data.oLeft = 0
      } else if (data.oLeft >= slider.value.offsetWidth - btn.value.offsetWidth) {
        data.oLeft = slider.value.offsetWidth - btn.value.offsetWidth
      }
      btn.value.style.transform = `translateX(${data.oLeft}px)`
      track.value.style.width = `${data.oLeft}px`
    }
  }

  const isError = () => {
    stage.value.classList.add('login-error')
    stage.value.addEventListener(
      'animationend',
      () => {
        if (data.isSuccess === state[1] || data.isSuccess === state[0]) {
          btn.value.style.transform = `translateX(${0}px)`
          track.value.style.width = 0
          if (stage.value.classList.contains('login-error')) {
            stage.value.classList.remove('login-error')
            data.isSuccess = state[0]
          }
        }
      },
      false,
    )
  }
  const touchend = () => {
    if (data.oLeft >= slider.value.clientWidth - btn.value.offsetWidth) {
      btn.value.style.transform = `translateX(${data.oLeft}px)`
      data.isMove = false
      track.value.style.width = `${data.oLeft}px`
      data.isSuccess = state[2]
    } else {
      data.isSuccess = state[1]
      isError()
    }
    btn.value.className = 'button-on'
    track.value.className = 'track-on'
  }
  const validate = (): boolean => {
    if (data.isSuccess === state[0] || data.isSuccess === state[1]) {
      isError()
      return false
    }
    return true
  }
  // 暴露一个获取验证的方法
  defineExpose({ validate })
 @keyframes slidetounlock {
    0% {
      background-position: -200px 0;
    }
    100% {
      background-position: 200px 0;
    }
  }
  @-webkit-keyframes slidetounlock {
    0% {
      background-position: -200px 0;
    }
    100% {
      background-position: 200px 0;
    }
  }
  @-webkit-keyframes bouncedelay {
    0%,
    80%,
    100% {
      -webkit-transform: scale(0);
    }
    40% {
      -webkit-transform: scale(1);
    }
  }
  @keyframes bouncedelay {
    0%,
    80%,
    100% {
      transform: scale(0);
      -webkit-transform: scale(0);
    }
    40% {
      transform: scale(1);
      -webkit-transform: scale(1);
    }
  }
  @keyframes errtips {
    10% {
      transform: translateX(3px);
    }
    20% {
      transform: translateX(-3px);
    }
    30% {
      transform: translateX(3px);
    }
    40% {
      transform: translateX(-3px);
    }
    50% {
      transform: translateX(3px);
    }
    60% {
      transform: translateX(-3px);
    }
    70% {
      transform: translateX(3px);
    }
    80% {
      transform: translateX(-3px);
    }
    90% {
      transform: translateX(3px);
    }
    100% {
      transform: translateX(0);
    }
  }
  .login-error {
    border: 1px solid red !important;
    animation: errtips 0.5s;
    .text {
      color: red;
    }
  }
  .stage {
    position: relative;
    height: 44px;
    border: 1px solid #ccc;
    width: 100%;
    .slider {
      position: absolute;
      height: 100%;
      width: 100%;
    }
    .label {
      background-image: -webkit-linear-gradient(
        left,
        #e9a5a5,
        #b8c1c0 10%,
        #65c0e0 20%,
        #aea2db 30%,
        #81c1d9 40%,
        #e9a5a5 50%,
        #b8c1c0 60%,
        #65c0e0 70%,
        #aea2db 80%,
        #81c1d9 90%,
        #e9a5a5
      );
      font-weight: 800;
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      -webkit-animation: slidetounlock 3s infinite;
      -webkit-text-size-adjust: none;
      line-height: 44px;
      height: 100%;
      text-align: center;
      font-size: 14px;
      width: 100%;
      color: #aaa;
    }

    .button {
      position: absolute;
      left: 0;
      top: 0;
      width: 40px;
      height: 100%;
      background: #fff;
      transition: all 0s;
      color: #ccc;
      -webkit-transition: all 0s;
    }
    .button-on {
      position: absolute;
      left: 0;
      top: 0;
      width: 40px;
      height: 100%;
      background-color: #fff;
      transition: all 1s;
      -webkit-transition: all 0.5s;
    }
    .track {
      position: absolute;
      left: 0;
      top: 0;
      height: 100%;
      width: 0;
      overflow: hidden;
      transition: width 0s;
      -webkit-transition: width 0s;
    }
    .track-on {
      position: absolute;
      left: 0;
      top: 0;
      height: 100%;
      width: 0;
      overflow: hidden;
      transition: width 1s;
      -webkit-transition: width 0.5s;
    }
    .icon {
      height: 100%;
      width: 100%;
      color: #ccc;
      font-size: 25px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .bg-green {
      line-height: 34px;
      height: 100%;
      text-align: center;
      font-size: 14px;
      background-color: var(--van-button-primary-background-color);
      color: #fff;
    }
  }

引用

 <van-field>
  <template #input><slidingVerification ref="validate" /></template>
</van-field>
<script lang="ts" setup>
  import { reactive } from 'vue'
  import slidingVerification from '@/components/slidingVerification.vue'
  const validate = ref()
  // 获取是否验证通过
   validate.value.validate()
</script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值