我的编程空间,编程开发者的网络收藏夹
学习永远不晚

vue实现图片滑动验证

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

vue实现图片滑动验证

本文实例为大家分享了vue实现图片滑动验证的具体代码,供大家参考,具体内容如下

效果图:

1、引用自定义组件

import img0 from '../assets/img.jpg';
import img1 from '../assets/img1.jpg';
import img2 from '../assets/img2.jpg';
import img3 from '../assets/img3.jpg';
import img4 from '../assets/img4.jpg';
import img5 from '../assets/img5.jpg';
import solide from "../conponents/phptoSlide"
components: {
    solide
  },

2、使用

<solide ref="slideblock" @success="onSuccess" @again="onAgain" @fulfilled="onFulfilled"
   @fail="onFail" @refresh="onRefresh" :slider-text="text" :imgs="imgs" :accuracy="accuracy">
  </solide>
  
data () {
    return {
      msg: '',
      text: '向右滑动->',
      imgs: [
        img0,
        img1,
        img2,
        img3,
        img4,
        img5,
      ],
      loginBtn: false,
      accuracy: 1, // 精确度小,可允许的误差范围小;为1时,则表示滑块要与凹槽完全重叠,才能验证成功。默认值为5
      formLabelAlign: {},
    }
 }
  methods: {
    onSuccess (times) {
      // console.log('验证通过');
      this.loginBtn = true;
      this.msg = `login success, 耗时${(times / 1000).toFixed(1)}s`;
    },
    onFail () {
      // console.log('验证不通过');
      this.msg = ''
    },
    onRefresh () {
      // console.log('点击了刷新小图标');
      this.msg = ''
    },
    onFulfilled () {
      // console.log('刷新成功啦!');
    },
    onAgain () {
      // console.log('检测到非人为操作的哦!');
      this.msg = 'try again';
      // 刷新
      this.handleClick();
    },
    handleClick () {
      this.$refs.slideblock.reset();
      this.msg = ''
    },
  }

3、自定义组件文件

<template>
  <div class="slide-verify" :style="{width: w + 'px'}" id="slideVerify" onselectstart="return false;">
    <!-- 图片加载遮蔽罩 -->
    <div :class="{'slider-verify-loading': loadBlock}"></div>
    <canvas :width="w" :height="h" ref="canvas"></canvas>
    <div v-if="show" @click="refresh" class="slide-verify-refresh-icon"></div>
    <canvas :width="w" :height="h" ref="block" class="slide-verify-block"></canvas>
    <!-- container -->
    <div class="slide-verify-slider" :class="{'container-active': containerActive, 'container-success': containerSuccess, 'container-fail': containerFail}">
      <div class="slide-verify-slider-mask" :style="{width: sliderMaskWidth}">
        <!-- slider -->
        <div @mousedown="sliderDown" @touchstart="touchStartEvent" @touchmove="touchMoveEvent" @touchend="touchEndEvent" class="slide-verify-slider-mask-item" :style="{left: sliderLeft}">
          <div class="slide-verify-slider-mask-item-icon"></div>
        </div>
      </div>
      <span class="slide-verify-slider-text">{{sliderText}}</span>
    </div>
  </div>
</template>
<script>
const PI = Math.PI;

function sum (x, y) {
  return x + y
}

function square (x) {
  return x * x
}
export default {
  name: 'SlideVerify',
  props: {
    // block length
    l: {
      type: Number,
      default: 30,
    },
    // block radius
    r: {
      type: Number,
      default: 6,
    },
    // canvas width
    w: {
      type: Number,
      default: 270,
    },
    // canvas height
    h: {
      type: Number,
      default: 90,
    },
    sliderText: {
      type: String,
      default: 'Slide filled right',
    },
    accuracy: {
      type: Number,
      default: 5, // 若为 -1 则不进行机器判断
    },
    show: {
      type: Boolean,
      default: true,
    },
    imgs: {
      type: Array,
      default: () => [],
    },
  },
  data () {
    return {
      containerActive: false, // container active class
      containerSuccess: false, // container success class
      containerFail: false, // container fail class
      canvasCtx: null,
      blockCtx: null,
      block: null,
      block_x: undefined, // container random position
      block_y: undefined,
      L: this.l + this.r * 2 + 3, // block real lenght
      img: undefined,
      originX: undefined,
      originY: undefined,
      isMouseDown: false,
      trail: [],
      sliderLeft: 0, // block right offset
      sliderMaskWidth: 0, // mask width,
      success: false, // Bug Fixes 修复了验证成功后还能滑动
      loadBlock: true, // Features 图片加载提示,防止图片没加载完就开始验证
      timestamp: null,
    }
  },
  mounted () {
    this.init()
  },
  methods: {
    init () {
      this.initDom()
      this.initImg()
      this.bindEvents()
    },
    initDom () {
      this.block = this.$refs.block;
      this.canvasCtx = this.$refs.canvas.getContext('2d')
      this.blockCtx = this.block.getContext('2d')
    },
    initImg () {
      const img = this.createImg(() => {
        // 图片加载完关闭遮蔽罩
        this.loadBlock = false;
        this.drawBlock()
        this.canvasCtx.drawImage(img, 0, 0, this.w, this.h)
        this.blockCtx.drawImage(img, 0, 0, this.w, this.h)
        let {
          block_x: x,
          block_y: y,
          r,
          L
        } = this
        let _y = y - r * 2 - 1
        let ImageData = this.blockCtx.getImageData(x, _y, L, L);
        this.block.width = L;
        this.blockCtx.putImageData(ImageData, 0, _y)
      });
      this.img = img;
    },
    drawBlock () {
      this.block_x = this.getRandomNumberByRange(this.L + 10, this.w - (this.L + 10))
      this.block_y = this.getRandomNumberByRange(10 + this.r * 2, this.h - (this.L + 10))
      this.draw(this.canvasCtx, this.block_x, this.block_y, 'fill')
      this.draw(this.blockCtx, this.block_x, this.block_y, 'clip')
    },
    draw (ctx, x, y, operation) {
      let {
        l,
        r
      } = this;
      ctx.beginPath()
      ctx.moveTo(x, y)
      ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI)
      ctx.lineTo(x + l, y)
      ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI)
      ctx.lineTo(x + l, y + l)
      ctx.lineTo(x, y + l)
      ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true)
      ctx.lineTo(x, y)
      ctx.lineWidth = 2
      ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
      ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)'
      ctx.stroke()
      ctx[operation]()
      // Bug Fixes 修复了火狐和ie显示问题
      ctx.globalCompositeOperation = "destination-over"
    },
    createImg (onload) {
      const img = document.createElement('img');
      img.crossOrigin = "Anonymous";
      img.onload = onload;
      img.onerror = () => {
        img.class="lazy" data-src = this.getRandomImg()
      }
      img.class="lazy" data-src = this.getRandomImg()
      return img;
    },
    // 随机生成img class="lazy" data-src
    getRandomImg () {
      // return require('../assets/img.jpg')
      const len = this.imgs.length;
      return len > 0 ?
        this.imgs[this.getRandomNumberByRange(0, len)] :
        'https://picsum.photos/300/150/?image=' + this.getRandomNumberByRange(0, 1084);
    },
    getRandomNumberByRange (start, end) {
      return Math.round(Math.random() * (end - start) + start)
    },
    refresh () {
      this.reset()
      this.$emit('refresh')
    },
    sliderDown (event) {
      if (this.success) return;
      this.originX = event.clientX;
      this.originY = event.clientY;
      this.isMouseDown = true;
      this.timestamp = + new Date();
    },
    touchStartEvent (e) {
      if (this.success) return;
      this.originX = e.changedTouches[0].pageX;
      this.originY = e.changedTouches[0].pageY;
      this.isMouseDown = true;
      this.timestamp = + new Date();
    },
    bindEvents () {
      document.addEventListener('mousemove', (e) => {
        if (!this.isMouseDown) return false;
        const moveX = e.clientX - this.originX;
        const moveY = e.clientY - this.originY;
        if (moveX < 0 || moveX + 38 >= this.w) return false;
        this.sliderLeft = moveX + 'px';
        let blockLeft = (this.w - 40 - 20) / (this.w - 40) * moveX;
        this.block.style.left = blockLeft + 'px';

        this.containerActive = true; // add active
        this.sliderMaskWidth = moveX + 'px';
        this.trail.push(moveY);
      });
      document.addEventListener('mouseup', (e) => {
        if (!this.isMouseDown) return false
        this.isMouseDown = false
        if (e.clientX === this.originX) return false;
        this.containerActive = false; // remove active
        this.timestamp = + new Date() - this.timestamp;

        const {
          spliced,
          TuringTest
        } = this.verify();
        if (spliced) {
          if (this.accuracy === -1) {
            this.containerSuccess = true;
            this.success = true;
            this.$emit('success', this.timestamp);
            return;
          }
          if (TuringTest) {
            // succ
            this.containerSuccess = true;
            this.success = true;
            this.$emit('success', this.timestamp)
          } else {
            this.containerFail = true;
            this.$emit('again')
          }
        } else {
          this.containerFail = true;
          this.$emit('fail')
          setTimeout(() => {
            this.reset()
          }, 1000)
        }
      })
    },
    touchMoveEvent (e) {
      if (!this.isMouseDown) return false;
      const moveX = e.changedTouches[0].pageX - this.originX;
      const moveY = e.changedTouches[0].pageY - this.originY;
      if (moveX < 0 || moveX + 38 >= this.w) return false;
      this.sliderLeft = moveX + 'px';
      let blockLeft = (this.w - 40 - 20) / (this.w - 40) * moveX;
      this.block.style.left = blockLeft + 'px';

      this.containerActive = true;
      this.sliderMaskWidth = moveX + 'px';
      this.trail.push(moveY);
    },
    touchEndEvent (e) {
      if (!this.isMouseDown) return false
      this.isMouseDown = false
      if (e.changedTouches[0].pageX === this.originX) return false;
      this.containerActive = false;
      this.timestamp = + new Date() - this.timestamp;

      const {
        spliced,
        TuringTest
      } = this.verify();
      if (spliced) {
        if (this.accuracy === -1) {
          this.containerSuccess = true;
          this.success = true;
          this.$emit('success', this.timestamp);
          return;
        }
        if (TuringTest) {
          // succ
          this.containerSuccess = true;
          this.success = true;
          this.$emit('success', this.timestamp)
        } else {
          this.containerFail = true;
          this.$emit('again')
        }
      } else {
        this.containerFail = true;
        this.$emit('fail')
        setTimeout(() => {
          this.reset()
        }, 1000)
      }
    },
    verify () {
      const arr = this.trail // drag y move distance
      const average = arr.reduce(sum) / arr.length // average
      const deviations = arr.map(x => x - average) // deviation array
      const stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length) // standard deviation
      const left = parseInt(this.block.style.left)
      const accuracy = this.accuracy <= 1 ? 1 : this.accuracy > 10 ? 10 : this.accuracy;
      return {
        spliced: Math.abs(left - this.block_x) <= accuracy,
        TuringTest: average !== stddev, // equal => not person operate
      }
    },
    reset () {
      this.success = false;
      this.containerActive = false;
      this.containerSuccess = false;
      this.containerFail = false;
      this.sliderLeft = 0;
      this.block.style.left = 0;
      this.sliderMaskWidth = 0;
      // canvas
      let {
        w,
        h
      } = this;
      this.canvasCtx.clearRect(0, 0, w, h)
      this.blockCtx.clearRect(0, 0, w, h)
      this.block.width = w

      // generate img
      this.img.class="lazy" data-src = this.getRandomImg();
      this.$emit('fulfilled')
    },
  }
}
</script>
<style scoped>
.slide-verify {
  position: relative;
}


.slider-verify-loading {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.9);
  z-index: 999;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% {
    opacity: 0.7;
  }
  100% {
    opacity: 9;
  }
}

.slide-verify-block {
  position: absolute;
  left: 0;
  top: 0;
}

.slide-verify-refresh-icon {
  position: absolute;
  right: 0;
  top: 0;
  width: 34px;
  height: 34px;
  cursor: pointer;
  background: url("../assets/icon_light.png") 0 -437px;
  background-size: 34px 471px;
}

.slide-verify-slider {
  position: relative;
  text-align: center;
  width: 100%;
  height: 40px;
  line-height: 40px;
  
  background: #f7f9fa;
  color: #45494c;
  border: 1px solid #e4e7eb;
}

.slide-verify-slider-mask {
  position: absolute;
  left: 0;
  top: 0;
  height: 40px;
  border: 0 solid #1991fa;
  background: #d1e9fe;
}

.slide-verify-slider-mask-item {
  position: absolute;
  top: 0;
  left: 0;
  width: 40px;
  height: 40px;
  background: #fff;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  transition: background 0.2s linear;
}

.slide-verify-slider-mask-item:hover {
  background: #1991fa;
}

.slide-verify-slider-mask-item:hover .slide-verify-slider-mask-item-icon {
  background-position: 0 -13px;
}

.slide-verify-slider-mask-item-icon {
  position: absolute;
  top: 15px;
  left: 13px;
  width: 14px;
  height: 12px;
  background: url("../assets/icon_light.png") 0 -26px;
  background-size: 34px 471px;
}
.container-active .slide-verify-slider-mask-item {
  height: 38px;
  top: -1px;
  border: 1px solid #1991fa;
}

.container-active .slide-verify-slider-mask {
  height: 38px;
  border-width: 1px;
}

.container-success .slide-verify-slider-mask-item {
  height: 38px;
  top: -1px;
  border: 1px solid #52ccba;
  background-color: #52ccba !important;
}

.container-success .slide-verify-slider-mask {
  height: 38px;
  border: 1px solid #52ccba;
  background-color: #d2f4ef;
}

.container-success .slide-verify-slider-mask-item-icon {
  background-position: 0 0 !important;
}

.container-fail .slide-verify-slider-mask-item {
  height: 38px;
  top: -1px;
  border: 1px solid #f57a7a;
  background-color: #f57a7a !important;
}

.container-fail .slide-verify-slider-mask {
  height: 38px;
  border: 1px solid #f57a7a;
  background-color: #fce1e1;
}

.container-fail .slide-verify-slider-mask-item-icon {
  top: 14px;
  background-position: 0 -82px !important;
}

.container-active .slide-verify-slider-text,
.container-success .slide-verify-slider-text,
.container-fail .slide-verify-slider-text {
  display: none;
}
</style>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

vue实现图片滑动验证

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

vue 实现左滑图片验证功能

网页中滑动图片验证一直是各大网站、移动端的主流校验方式,其主要作用是为了区分人和机器以及为了防止机器人程序暴力登录或攻击从而设置的一种安全保护方式,这篇文章主要介绍了vue 实现左滑图片验证,需要的朋友可以参考下
2023-05-14

vue如何实现左滑图片验证功能

这篇“vue如何实现左滑图片验证功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“vue如何实现左滑图片验证功能”文章吧。一
2023-07-05

Python实现图片滑动式验证识别方法

1 abstract 验证码作为一种自然人的机器人的判别工具,被广泛的用于各种防止程序做自动化的场景中。传统的字符型验证安全性已经名存实亡的情况下,各种新型的验证码如雨后春笋般涌现。目前最常见的一种形式就是“滑动拼图式” 2 内容概述 关于
2022-06-04

vue怎么实现滑动验证条

这篇文章主要介绍“vue怎么实现滑动验证条”,在日常操作中,相信很多人在vue怎么实现滑动验证条问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue怎么实现滑动验证条”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-29

PHP如何实现滑块验证图片

这篇文章主要讲解了“PHP如何实现滑块验证图片”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP如何实现滑块验证图片”吧!安装composer require kkokk/poster更新
2023-07-04

Vue如何实现滑动验证功能

这篇文章主要介绍了Vue如何实现滑动验证功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。用Vue实现滑动验证码,鼠标点击滑动验证,验证成功之后会显示验证通过。程序分析1、鼠
2023-06-29

vue怎么自定义开发滑动图片验证组件

这篇文章主要介绍了vue怎么自定义开发滑动图片验证组件的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue怎么自定义开发滑动图片验证组件文章都会有所收获,下面我们一起来看看吧。纯前端,通过canvas来自定义开
2023-06-29

编程热搜

目录