vue实现图片滑动验证
更新时间:2022年03月02日 15:50:54 作者:阳光下的雨u
这篇文章主要为大家详细介绍了vue实现图片滑动验证,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud)
(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun)
本文实例为大家分享了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.src = this.getRandomImg() ? ? ? } ? ? ? img.src = this.getRandomImg() ? ? ? return img; ? ? }, ? ? // 随机生成img 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.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; ? /* margin-top: 15px; */ ? 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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持程序员之家。
最新评论