首页

源码搜藏网

首页 > 开发教程 > js/jQuery教程 >

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

创建时间:2022-03-31 17:03  

纯前端,通过canvas来自定义开发滑动图片验证,反过来也能完成纯滑动验证。

<template>
 <div class="verification" ref="verification">
  <!-- 画布部分 -->
  <canvas ref="slideVerify" class="slide-img"></canvas>
  <div style="display:none">
   <img ref="imgs" :src="imgList[imgIndex]"/>
  </div>
  <!-- 下面滑块部分 -->
  <div class="slide-wrapper bg-start">
   <!-- 滑块 -->
   <div class="btn" ref="btn" @mousedown="mouseDown" @mouseup="mouseUp"></div>
   <p class="text" ref="text">{{content}}</p>
   <div class="bg" ref="bg"></div>
  </div>
  <!-- 刷新按钮 -->
  <button class="refresh" @click="refresh"></button>
 </div>
</template>

<script>
export default {
 data () {
  return {
   imgIndex: 0,
   blockCanvas: null,
   imgList: [require('../assets/1.png'),
    require('../assets/3.png'),
    require('../assets/4.png'),
    require('../assets/5.png') ],
   content: '滑动滑块',
   isDown: false, // 鼠标是否按下
   btnX: 0,
   imgX: 0
  }
 },
 mounted () {
  this.imgIndex = this.randomNumber(0, 4)
  document.addEventListener('mousemove', this.mouseMove)
  this.imageCanvas()
 },
 methods: {
  // 生成随机数字
  randomNumber (min, max) {
   return Math.floor(Math.random() * (max - min) + min)
  },
  // 鼠标按下时
  mouseDown (e) {
   this.isDown = true
   this.btnX = e.clientX - this.$refs.btn.offsetLeft
  },
  // 鼠标滑动时
  mouseMove (e) {
   // 滑块左端向右边移动的距离
   let moveX = e.clientX - this.btnX
   if (this.isDown) {
    // 滑块滑动时不能超过的距离
    if (this.$refs.btn.offsetLeft <= 259 && this.$refs.btn.offsetLeft >= 0) {
     this.$refs.btn.style.left = `${moveX}px`
     this.blockCanvas.style.left = `${moveX - this.imgX}px`
     this.$refs.bg.style.width = `${moveX}px`
    }
   }
  },
  // 滑动中松开
  mouseUp () {
   let leftX = this.$refs.btn.offsetLeft
   // 方块的位置和缺失的位置重合允许左右2px的误差
   if (this.imgX >= leftX - 1 && this.imgX <= leftX + 1) {
    // 滑动成功时的逻辑
    this.$refs.btn.classList.add('btnsuccess')
    this.isDown = false
   }
   // 如果滑动失败,滑块自动回到左边
   if (this.isDown) {
    this.$refs.btn.style.left = 0
    this.blockCanvas.style.left = `-${this.imgX}px`
    this.$refs.bg.style.width = 0
   }
   // 开关原则
   this.isDown = false
  },
  // 画图
  imageCanvas () {
   this.blockCanvas = this.blockCanvas  this.blockCanvas.remove() : null
   this.blockCanvas = this.createCanvas(300, 150)
   this.$refs.verification.insertBefore(this.blockCanvas, this.$refs.slideVerify)
   let x = this.randomNumber(60, 200)
   let y = 40
   this.imgX = x
   let c = this.$refs.slideVerify
   let bg = c.getContext('2d')
   let img = this.$refs.imgs
   let bk = this.blockCanvas.getContext('2d')
   // 在两块画布上都放上相同的图片
   img.onload = () => {
    bg.drawImage(img, 0, 0)
    bk.drawImage(img, 0, 0)
   }
   this.drawBlock(bg, x, y, 'fill')
   this.drawBlock(bk, x, y, 'clip')
  },
  // 画抠出来的方块
  drawBlock (ctx, x, y, type) {
   ctx.beginPath()
   ctx.moveTo(x, y)
   ctx.arc(x + 42 / 2, y - 9 + 2, 9, 0.72 * Math.PI, 2.26 * Math.PI)
   ctx.lineTo(x + 42, y)
   ctx.arc(x + 42 + 9 - 2, y + 42 / 2, 9, 1.21 * Math.PI, 2.78 * Math.PI)
   ctx.lineTo(x + 42, y + 42)
   ctx.lineTo(x, y + 42)
   ctx.arc(x + 9 - 2, y + 42 / 2, 9 + 0.4, 2.76 * Math.PI, 1.24 * Math.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[type]()
   ctx.globalCompositeOperation = 'destination-over'
   // 解决进入页面时不自动扣拼图样式的麻烦(有时需要鼠标点击后才会出现裁剪后的拼图)
   this.blockCanvas.style.left = `-${x}px`
  },
  // 刷新
  refresh () {
   // 有时会出现点击刷新,randomNumber返回的数字和上次存储的一样,画布清空后但是填充时没有改变;所以当一样时,不会执行刷新操作
   if (this.imgIndex == this.randomNumber(0, 4)) {
    return false
   }
   this.clean()
   this.$refs.btn.style.left = 0
   this.$refs.bg.style.width = 0
   this.$refs.btn.classList.remove('btnsuccess')
   this.isDown = false // 鼠标是否按下
   this.btnX = 0 // 鼠标点击的水平位置与滑块移动水平位置的差
   this.imgX = 0
   this.imageCanvas('restore')
   this.imgIndex = this.randomNumber(0, 4)
  },
  // 清空canvas
  clean () {
   let cxt2 = this.$refs.slideVerify.getContext('2d')
   cxt2.clearRect(0, 0, 300, 150)
  },
  // 新建canvas
  createCanvas (width, height) {
   const canvas = document.createElement('canvas')
   canvas.width = width
   canvas.height = height
   canvas.style.position = 'absolute'
   return canvas
  }
 }
}
</script>

<style scoped>
.verification {
 position: relative;
 width: 300px;
 margin: 0 auto;
}
.slide-wrapper {
 position: relative;
 width: 300px;
 height: 40px;
}
.bg-start {
 background: cadetblue;
}
.bg {
 position: absolute;
 height: 40px;
 background: #ccc;
}
.text {
 position: absolute;
 width: 100%;
 height: 40px;
 text-align: center;
 line-height: 40px;
 margin: 0;
 /* z-index: 1; */
}
.text-success {
 color: white;
 z-index: 2;
}
.btn {
 position: absolute;
 width: 40px;
 height: 40px;
 z-index: 1;
 border-radius: 5px;
 background: rgb(143, 145, 148);
 text-align: center;
 font-size: 24px;
 color: white;
 box-shadow: 0 0 1px 1px #fff;
 background: #fff no-repeat center url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==");
}
.btnsuccess {
 background: #fff no-repeat center url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==");
}
.refresh {
  cursor: pointer;
  width: 20px;
  height: 20px;
  position: absolute;
  z-index: 1;
  top: 0;
  right: 10px;
  opacity: .6;
  background: url('../assets/ref.jpg') no-repeat;
  background-size: cover;
}
</style>

完成效果图

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

滑动完成时

因为允许1px的差距,可以自己改

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

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

上一篇:javascript实现悬浮跟随框缓动效果
下一篇:没有了

相关内容

热门推荐