<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
vue拖住滾軸拼圖驗證,以下是cavas直接寫的滾軸拼圖驗證碼,直接複製參照即可
<template> <div id="puzzle" ref="puzzle" style="display:inline-block;"> <!-- :style="'padding:' + 16*scale + 'px ' + 16*scale + 'px ' + 28*scale + 'px;border-radius:'+16*scale+'px;'" --> <div class="puzzle-container" > <div :style="'position:relative;overflow:hidden;width:'+ dataWidth +'px;'"> <div :style="'position:relative;width:' + dataWidth + 'px;height:' + dataHeight + 'px;'"> <img id="scream" ref="scream" :src="imgRandom" :style="'width:' + dataWidth + 'px;height:' + dataHeight + 'px;'" /> <canvas id="puzzle-box" ref="puzzleBox" :width="dataWidth" :height="dataHeight"></canvas> </div> <div class="puzzle-lost-box" :style="'left:' + left_Num + 'px;width:' + dataWidth + 'px;height:' + dataHeight + 'px;'" > <canvas id="puzzle-shadow" ref="puzzleShadow" :width="dataWidth" :height="dataHeight"></canvas> <canvas id="puzzle-lost" ref="puzzleLost" :width="dataWidth" :height="dataHeight"></canvas> </div> <p class="ver-tips" ref="verTips" :style="'height: '+22*scale+'px;line-height:'+22*scale+'px;bottom: ' + (displayTips==true ? 0 : -22*scale ) +'px;font-size: '+12*scale+'px;'" > <template v-if="verification"> <span :style="'color:#42ca6b;line-height:'+ 22*scale+'px;'">驗證通過</span> <span :style="'margin-left:'+4*scale+'px;line-height:'+ 22*scale+'px;'">哇喔,怪物吃了拼圖,快去登入吧~</span> </template> <template v-if="!verification"> <span :style="'color:red;line-height:'+22*scale+'px;'">驗證失敗:</span> <span :style="'margin-left:'+4*scale+'px;line-height:'+ 22*scale+'px;'">拖動滾軸將懸浮影象正確拼合</span> </template> </p> </div> <div class="re-btn" @click="refreshImg" :style="'height: '+28*scale+'px;padding: '+1*scale+'px '+16*scale+'px;font-size: '+18*scale+'px;'" > <a-icon type="redo" /> </div> </div> <br /> <div class="slider-container" :style="'width:' + dataWidth + 'px;'"> <div class="slider-bar" :style="'border-radius:'+ 24*scale+'px;'"> <p class="slider-bar-text select-none" onselectstart="return false" :style="'line-height:' + 28*scale + 'px;font-size:'+12*scale+'px;'" >按住滾軸, 拖動完成上方拼圖</p> </div> <div class="slider-btn" ref="sliderBtn" @mousedown="startMove" @touchstart="startMove" :style="'top: '+ -7*scale + 'px;'" > <a-icon type="pause-circle" theme="twoTone" twoToneColor="#52c41a" :style="'font-size: '+44*scale+'px;'" /> <span class="slider-center-zzz">▍▍▍</span> </div> </div> </div> </template> <script lang="js"> export default { name: 'puzzle', data () { return { moveStart: '', displayTips: false, verification: false, randomX: null, randomY: null, imgRandom: '', left_Num: 0, dataWidth: 404, dataHeight: 90, puzzleSize: 100, deviation: 11, scale: 1, reTimer: null, isleavePage: false } }, props: { width: { type: [String, Number], default: 340 }, height: { type: [String, Number], default: 120 }, cropImage: { type: [Boolean], default: false }, puzzleImgList: { type: Array, default: () => [ '../../../static/img/a.png', ] }, PlSize: { type: [String, Number], default: 48 }, Deviation:{ type: [String, Number], default: 4 }, padding: { type: [Number], default: 20 }, onSuccess: { type: Function, default: () => { alert('驗證成功') } }, onError: { type: Function, default: () => { alert('驗證失敗') } } }, methods: { /* 重新整理 */ RandomNum(Min, Max) { let Range = Max - Min + 1 let Rand = Math.random() return Min + Math.floor(Rand * Range) }, refreshImg () { let imgRandomNum = this.RandomNum(0, this.puzzleImgList.length-1) this.imgRandom = this.puzzleImgList[imgRandomNum] this.initCanvas() }, /* 畫布初始化 */ initCanvas () { this.clearCanvas() // let self = this let w = this.dataWidth let h = this.dataHeight // let PL_Size = 48 // 2019-02-12開始PL_Size使用可傳遞引數 let PL_Size = this.puzzleSize let padding = 20 let MinN_X = padding + PL_Size let MaxN_X = w - padding - PL_Size - PL_Size / 6 let MaxN_Y = padding let MinN_Y = h - padding - PL_Size - PL_Size / 6 this.randomX = this.RandomNum(MinN_X, MaxN_X) this.randomY = this.RandomNum(MinN_Y, MaxN_Y) let X = this.randomX let Y = this.randomY this.left_Num = -X + 10 let d = PL_Size / 3 let c = this.$refs.puzzleBox let c_l = this.$refs.puzzleLost let c_s = this.$refs.puzzleShadow let ctx = c.getContext('2d') let ctx_l = c_l.getContext('2d') let ctx_s = c_s.getContext('2d') ctx.globalCompositeOperation = 'xor' ctx.shadowBlur = 10 ctx.shadowColor = '#fff' ctx.shadowOffsetX = 3 ctx.shadowOffsetY = 3 ctx.fillStyle = 'rgba(0,0,0,0.7)' ctx.beginPath() ctx.lineWidth = '1' ctx.strokeStyle = 'rgba(0,0,0,0)' ctx.moveTo(X, Y) ctx.lineTo(X + d, Y) ctx.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y) ctx.lineTo(X + 3 * d, Y) ctx.lineTo(X + 3 * d, Y + d) ctx.bezierCurveTo(X + 2 * d, Y + d, X + 2 * d, Y + 2 * d, X + 3 * d, Y + 2 * d) ctx.lineTo(X + 3 * d, Y + 3 * d) ctx.lineTo(X, Y + 3 * d) ctx.closePath() ctx.stroke() ctx.fill() let img = new Image() img.src = this.imgRandom img.onload = function () { ctx_l.beginPath() ctx_l.strokeStyle = 'rgba(0,0,0,0)' ctx_l.moveTo(X, Y) ctx_l.lineTo(X + d, Y) ctx_l.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y) ctx_l.lineTo(X + 3 * d, Y) ctx_l.lineTo(X + 3 * d, Y + d) ctx_l.bezierCurveTo(X + 2 * d, Y + d, X + 2 * d, Y + 2 * d, X + 3 * d, Y + 2 * d) ctx_l.lineTo(X + 3 * d, Y + 3 * d) ctx_l.lineTo(X, Y + 3 * d) ctx_l.closePath() ctx_l.stroke() ctx_l.shadowBlur = 10 ctx_l.shadowColor = 'black' ctx_l.clip() ctx_l.drawImage(img, 0, 0, w, h) } ctx_s.beginPath() ctx_s.lineWidth = '1' ctx_s.strokeStyle = 'rgba(0,0,0,0)' ctx_s.moveTo(X, Y) ctx_s.lineTo(X + d, Y) ctx_s.bezierCurveTo(X + d, Y - d, X + 2 * d, Y - d, X + 2 * d, Y) ctx_s.lineTo(X + 3 * d, Y) ctx_s.lineTo(X + 3 * d, Y + d) ctx_s.bezierCurveTo(X + 2 * d, Y + d, X + 2 * d, Y + 2 * d, X + 3 * d, Y + 2 * d) ctx_s.lineTo(X + 3 * d, Y + 3 * d) ctx_s.lineTo(X, Y + 3 * d) ctx_s.closePath() ctx_s.stroke() ctx_s.shadowBlur = 20 ctx_s.shadowColor = 'black' ctx_s.fill() }, /* 通過重置畫布尺寸清空畫布,這種方式更徹底 */ clearCanvas () { let c = this.$refs.puzzleBox let c_l = this.$refs.puzzleLost let c_s = this.$refs.puzzleShadow c.setAttribute('height', c.getAttribute('height')) c_l.setAttribute('height', c.getAttribute('height')) c_s.setAttribute('height', c.getAttribute('height')) // c.height = c.height // c_l.height = c_l.height // c_s.height = c_s.height }, /* 按住滾軸後初始化移動監聽,記錄初始位置 */ startMove (e) { console.log(e) e = e || window.event this.$refs.sliderBtn.style.backgroundPosition = '0 -216px' this.moveStart = e.pageX || e.targetTouches[0].pageX this.addMouseMoveListener() }, /* 滾軸移動 */ moving (e) { let self = this e = e || window.event let moveX = e.pageX || e.targetTouches[0].pageX let d = moveX - self.moveStart let w = self.dataWidth let PL_Size = this.puzzleSize let padding = 20 if (self.moveStart === '') { return '' } if (d < 0 || d > (w - padding - PL_Size)) { return '' } self.$refs.sliderBtn.style.left = d + 'px' self.$refs.sliderBtn.style.transition = 'inherit' self.$refs.puzzleLost.style.left = d + 'px' self.$refs.puzzleLost.style.transition = 'inherit' self.$refs.puzzleShadow.style.left = d + 'px' self.$refs.puzzleShadow.style.transition = 'inherit' }, /* 移動結束,驗證並回撥 */ moveEnd (e) { let self = this e = e || window.event let moveEnd_X = (e.pageX || e.changedTouches[0].pageX) - self.moveStart let ver_Num = self.randomX - 10 let deviation = this.deviation let Min_left = ver_Num - deviation let Max_left = ver_Num + deviation if (self.moveStart !== '') { if (Max_left > moveEnd_X && moveEnd_X > Min_left) { self.displayTips = true self.verification = true setTimeout(function () { if(self.isleavePage){ return } self.displayTips = false self.initCanvas() }, 2000) /* 成功的回撥函數 */ self.onSuccess() } else { self.displayTips = true self.verification = false setTimeout(function () { if(self.isleavePage){ return } self.displayTips = false }, 2000) /* 失敗的回撥函數 */ self.onError() } } if (typeof(self.$refs.sliderBtn) !== 'undefined' && typeof (self.$refs.puzzleLost) !== 'undefined' && typeof (self.$refs.puzzleShadow) !== 'undefined') { self.reTimer = setTimeout(function () { if(self.isleavePage){ return } self.$refs.sliderBtn.style.left = 0 self.$refs.sliderBtn.style.transition = 'left 0.5s' self.$refs.puzzleLost.style.left = 0 self.$refs.puzzleLost.style.transition = 'left 0.5s' self.$refs.puzzleShadow.style.left = 0 self.$refs.puzzleShadow.style.transition = 'left 0.5s' }, 1000) self.$refs.sliderBtn.style.backgroundPosition = '0 -84px' } self.moveStart = '' }, /* 繫結滾軸移動與滑動結束,移動過程中滑鼠可在繫結的區域 */ addMouseMoveListener () { let self = this document.addEventListener('mousemove', self.moving) document.addEventListener('touchmove', self.moving) document.addEventListener('mouseup', self.moveEnd) document.addEventListener('touchend', self.moveEnd) } }, mounted () { let self = this this.dataWidth = this.$refs.puzzle.clientWidth*0.884 this.dataHeight = this.dataWidth*(this.height/this.width) this.scale = this.$refs.puzzle.clientWidth/260 this.puzzleSize = this.dataWidth*(this.PlSize/this.width) setTimeout(self.refreshImg,0) }, created () { let imgRandomNum = this.RandomNum(0, this.puzzleImgList.length - 1) this.imgRandom = this.puzzleImgList[imgRandomNum] this.puzzleSize = Number(this.PlSize) this.deviation = Number(this.Deviation) // this.dataWidth = this.width // this.dataHeight = this.height // this.scale = this.width/260 }, watch: { }, beforeDestroy() { this.isleavePage = true } } </script> <style scoped> .slider-btn { position: absolute; width: 90px; height: 67px; left: 0; top: -7px; z-index: 12; cursor: pointer; background-position: 0 -84px; transition: inherit; background-color: #f4f7fe; border-radius: 45%; display: flex; } .slider-center-zzz { text-align: center; line-height: 67px; position: absolute; color: #53C300; height: 40px; width: 100%; } .ver-tips { position: absolute; left: 0; bottom: -22px; background: rgba(255, 255, 255, 0.9); height: 22px; line-height: 22px; font-size: 12px; width: 100%; margin: 0; text-align: left; padding: 0 8px; transition: all 0.4s; } .slider-tips { bottom: 0; } .ver-tips i { display: inline-block; width: 22px; height: 22px; vertical-align: top; background-position: -4px -1229px; } .ver-tips span { display: inline-block; vertical-align: top; line-height: 22px; color: #455; } .active-tips { display: block; } .hidden { display: none; } .re-btn { position: absolute; left: 0; bottom: 0; height: 28px; padding: 0 16px; } .re-btn a { display: inline-block; width: 14px; height: 14px; margin: 0px 0; background-position: 0 -1179px; cursor: pointer; } .re-btn a:hover { background-position: 0 -1193px; } .puzzle-container { position: relative; /* padding: 16px 16px 28px; */ /* border: 1px solid #ddd; */ background: #e0e1e3; /* border-radius: 16px; */ /* height: 83px; */ /* width: 340px; */ } .slider-container { position: relative; margin: auto; } .slider-bar { border: 1px solid #c3c3c3; border-radius: 24px; background: #e0e1e3; box-shadow: 0 1px 1px rgba(12, 10, 10, 0.2) inset; } .slider-bar-text { font-size: 12px; color: #486c80; line-height: 28px; margin: 0; text-align: right; padding-right: 22px; } #puzzle-box { position: absolute; left: 0; top: 0; z-index: 22; } #puzzle-shadow { position: absolute; left: 0; top: 0; z-index: 22; } #puzzle-lost { position: absolute; left: 0; top: 0; z-index: 33; } .puzzle-lost-box { position: absolute; width: 260px; height: 116px; left: 0; top: 0; z-index: 111; } </style>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45