vue自定義開發(fā)滑動(dòng)圖片驗(yàn)證組件
純前端,通過(guò)canvas來(lái)自定義開發(fā)滑動(dòng)圖片驗(yàn)證,反過(guò)來(lái)也能完成純滑動(dòng)驗(yàn)證。
<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: '滑動(dòng)滑塊', ? ? ? isDown: false, // 鼠標(biāo)是否按下 ? ? ? btnX: 0,? ? ? ? imgX: 0? ? ? } ? }, ? mounted () { ? ? this.imgIndex = this.randomNumber(0, 4) ? ? document.addEventListener('mousemove', this.mouseMove) ? ? this.imageCanvas() ? }, ? methods: { ? ? // 生成隨機(jī)數(shù)字 ? ? randomNumber (min, max) { ? ? ? return Math.floor(Math.random() * (max - min) + min) ? ? }, ? ? // 鼠標(biāo)按下時(shí) ? ? mouseDown (e) { ? ? ? this.isDown = true ? ? ? this.btnX = e.clientX - this.$refs.btn.offsetLeft ? ? }, ? ? // 鼠標(biāo)滑動(dòng)時(shí) ? ? mouseMove (e) { ? ? ? // 滑塊左端向右邊移動(dòng)的距離 ? ? ? let moveX = e.clientX - this.btnX ? ? ? if (this.isDown) { ? ? ? ? // 滑塊滑動(dòng)時(shí)不能超過(guò)的距離 ? ? ? ? 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` ? ? ? ? } ? ? ? } ? ? }, ? ? // 滑動(dòng)中松開 ? ? mouseUp () { ? ? ? let leftX = this.$refs.btn.offsetLeft ? ? ? // 方塊的位置和缺失的位置重合允許左右2px的誤差 ? ? ? if (this.imgX >= leftX - 1 && this.imgX <= leftX + 1) { ? ? ? ? // 滑動(dòng)成功時(shí)的邏輯 ? ? ? ? this.$refs.btn.classList.add('btnsuccess') ? ? ? ? this.isDown = false ? ? ? } ? ? ? // 如果滑動(dòng)失敗,滑塊自動(dòng)回到左邊 ? ? ? if (this.isDown) { ? ? ? ? this.$refs.btn.style.left = 0 ? ? ? ? this.blockCanvas.style.left = `-${this.imgX}px` ? ? ? ? this.$refs.bg.style.width = 0 ? ? ? } ? ? ? // 開關(guān)原則 ? ? ? 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') ? ? }, ? ? // 畫摳出來(lái)的方塊 ? ? 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' ? ? ? // 解決進(jìn)入頁(yè)面時(shí)不自動(dòng)扣拼圖樣式的麻煩(有時(shí)需要鼠標(biāo)點(diǎn)擊后才會(huì)出現(xiàn)裁剪后的拼圖) ? ? ? this.blockCanvas.style.left = `-${x}px` ? ? }, ? ? // 刷新 ? ? refresh () { ? ? ? // 有時(shí)會(huì)出現(xiàn)點(diǎn)擊刷新,randomNumber返回的數(shù)字和上次存儲(chǔ)的一樣,畫布清空后但是填充時(shí)沒(méi)有改變;所以當(dāng)一樣時(shí),不會(huì)執(zhí)行刷新操作 ? ? ? 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 // 鼠標(biāo)是否按下 ? ? ? this.btnX = 0 // 鼠標(biāo)點(diǎn)擊的水平位置與滑塊移動(dòng)水平位置的差 ? ? ? 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>
完成效果圖
滑動(dòng)完成時(shí)
因?yàn)樵试S1px的差距,可以自己改
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue實(shí)現(xiàn)圖片滑動(dòng)驗(yàn)證功能
- vue實(shí)現(xiàn)登錄滑動(dòng)拼圖驗(yàn)證
- vue實(shí)現(xiàn)圖片滑動(dòng)驗(yàn)證
- vue實(shí)現(xiàn)滑動(dòng)驗(yàn)證條
- Vue實(shí)現(xiàn)滑動(dòng)驗(yàn)證功能
- Vue實(shí)現(xiàn)滑動(dòng)拼圖驗(yàn)證碼功能
- 使用Vue 實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼功能
- vue 登錄滑動(dòng)驗(yàn)證實(shí)現(xiàn)代碼
- Vue.js圖片滑動(dòng)驗(yàn)證的實(shí)現(xiàn)示例
相關(guān)文章
vue實(shí)現(xiàn)錨點(diǎn)跳轉(zhuǎn)及滾動(dòng)監(jiān)聽的方法
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)錨點(diǎn)跳轉(zhuǎn)及滾動(dòng)監(jiān)聽的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07vue實(shí)現(xiàn)日歷表格(element-ui)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)日歷表格(element-ui),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09Vue拖動(dòng)截圖功能的簡(jiǎn)單實(shí)現(xiàn)方法
最近項(xiàng)目上要做一個(gè)車牌識(shí)別的功能,就需要做拖動(dòng)截圖功能了,因?yàn)榍岸问莢ue,所以下面這篇文章主要給大家介紹了關(guān)于Vue拖動(dòng)截圖功能的簡(jiǎn)單實(shí)現(xiàn)方法,需要的朋友可以參考下2021-07-07el-form的label和表單自適應(yīng)填滿一行且靠左對(duì)齊方式
這篇文章主要介紹了el-form的label和表單自適應(yīng)填滿一行且靠左對(duì)齊方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vuex中store.commit和store.dispatch的區(qū)別及使用方法
這篇文章主要介紹了vuex中store.commit和store.dispatch的區(qū)別及使用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01