vue實(shí)現(xiàn)圖片滑動(dòng)驗(yàn)證
更新時(shí)間:2022年03月02日 15:50:54 作者:陽光下的雨u
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)圖片滑動(dòng)驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
本文實(shí)例為大家分享了vue實(shí)現(xiàn)圖片滑動(dòng)驗(yàn)證的具體代碼,供大家參考,具體內(nèi)容如下
效果圖:
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: '向右滑動(dòng)->', ? ? ? imgs: [ ? ? ? ? img0, ? ? ? ? img1, ? ? ? ? img2, ? ? ? ? img3, ? ? ? ? img4, ? ? ? ? img5, ? ? ? ], ? ? ? loginBtn: false, ? ? ? accuracy: 1, // 精確度小,可允許的誤差范圍小;為1時(shí),則表示滑塊要與凹槽完全重疊,才能驗(yàn)證成功。默認(rèn)值為5 ? ? ? formLabelAlign: {}, ? ? } ?} ? methods: { ? ? onSuccess (times) { ? ? ? // console.log('驗(yàn)證通過'); ? ? ? this.loginBtn = true; ? ? ? this.msg = `login success, 耗時(shí)${(times / 1000).toFixed(1)}s`; ? ? }, ? ? onFail () { ? ? ? // console.log('驗(yàn)證不通過'); ? ? ? this.msg = '' ? ? }, ? ? onRefresh () { ? ? ? // console.log('點(diǎn)擊了刷新小圖標(biāo)'); ? ? ? 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 則不進(jìn)行機(jī)器判斷 ? ? }, ? ? 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 修復(fù)了驗(yàn)證成功后還能滑動(dòng) ? ? ? loadBlock: true, // Features 圖片加載提示,防止圖片沒加載完就開始驗(yàn)證 ? ? ? 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(() => { ? ? ? ? // 圖片加載完關(guān)閉遮蔽罩 ? ? ? ? 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 修復(fù)了火狐和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; ? ? }, ? ? // 隨機(jī)生成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>
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue+echart?展示后端獲取的數(shù)據(jù)實(shí)現(xiàn)
本文主要介紹了Vue+echart?展示后端獲取的數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01vue里input根據(jù)value改變背景色的實(shí)例
今天小編就為大家分享一篇vue里input根據(jù)value改變背景色的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09vue3.x使用swiper實(shí)現(xiàn)卡片輪播
這篇文章主要為大家詳細(xì)介紹了vue3.x使用swiper實(shí)現(xiàn)卡片輪播,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07Vue3使用setup監(jiān)聽props實(shí)現(xiàn)方法詳解
這篇文章主要為大家介紹了Vue3使用setup監(jiān)聽props實(shí)現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08vue使用vue-video-player無法播放本地視頻的問題及解決
這篇文章主要介紹了vue使用vue-video-player無法播放本地視頻的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08