最近在做一个功能,前端实现随机验证码的生成,前端实现仅是单纯的一个小验证,若是想要实在的人机验证,还是需要由后端实现验证码的生成的。
1 // 第一种方法,span,不绘制干扰点 2 <template> 3 <div class="ValidCode disabled-select" :style="`${width}; height:${height}`" @click="refreshCode"> 4 <span v-for="(item, index) in codeList" :key="index" :style="getStyle(item)">{{item.code}}</span> 5 </div> 6 </template> 7 8 <script> 9 export default { 10 props: { 11 { 12 type: String, 13 default: '100px' 14 }, 15 height: { 16 type: String, 17 default: '34px' 18 }, 19 length: { 20 type: Number, 21 default: 4 22 } 23 }, 24 data () { 25 return { 26 codeList: [] 27 } 28 }, 29 mounted () { 30 this.createdCode() 31 }, 32 methods: { 33 refreshCode () { 34 this.createdCode() 35 }, 36 createdCode () { 37 const len = this.length 38 const codeList = [] 39 const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789' 40 const charsLen = chars.length 41 // 生成 42 for (let i = 0; i < len; i++) { 43 const rgb = [Math.round(Math.random() * 220), Math.round(Math.random() * 240), Math.round(Math.random() * 200)] 44 codeList.push({ 45 code: chars.charAt(Math.floor(Math.random() * charsLen)), 46 color: `rgb(${rgb})`, 47 fontSize: `1${[Math.floor(Math.random() * 10)]}px`, 48 padding: `${[Math.floor(Math.random() * 10)]}px`, 49 transform: `rotate(${Math.floor(Math.random() * 90) - Math.floor(Math.random() * 90)}deg)` 50 }) 51 } 52 // 指向 53 this.codeList = codeList 54 // 将当前数据派发出去 55 this.$emit('update:value', codeList.map(item => item.code).join('')) 56 }, 57 getStyle (data) { 58 return `color: ${data.color}; font-size: ${data.fontSize}; padding: ${data.padding}; transform: ${data.transform}` 59 } 60 } 61 } 62 </script> 63 64 <style scoped lang="scss"> 65 .ValidCode{ 66 display: flex; 67 justify-content: center; 68 align-items: center; 69 cursor: pointer; 70 span{ 71 display: inline-block; 72 } 73 } 74 </style>
1 // 第二种方法 canvas 绘制干扰点干扰线 2 <template> 3 <div class="s-canvas" @click="createdCode"> 4 <canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas> 5 </div> 6 </template> 7 <script> 8 import Vue from 'vue' 9 export default Vue.extend({ 10 props: { 11 fontSizeMin: { 12 type: Number, 13 default: 25 14 }, 15 fontSizeMax: { 16 type: Number, 17 default: 30 18 }, 19 backgroundColorMin: { 20 type: Number, 21 default: 255 22 }, 23 backgroundColorMax: { 24 type: Number, 25 default: 255 26 }, 27 colorMin: { 28 type: Number, 29 default: 0 30 }, 31 colorMax: { 32 type: Number, 33 default: 160 34 }, 35 lineColorMin: { 36 type: Number, 37 default: 100 38 }, 39 lineColorMax: { 40 type: Number, 41 default: 255 42 }, 43 dotColorMin: { 44 type: Number, 45 default: 0 46 }, 47 dotColorMax: { 48 type: Number, 49 default: 255 50 }, 51 contentWidth: { 52 type: Number, 53 default: 120 54 }, 55 contentHeight: { 56 type: Number, 57 default: 34 58 } 59 }, 60 data () { 61 return { 62 identifyCode: '' 63 } 64 }, 65 mounted () { 66 this.createdCode() 67 }, 68 methods: { 69 // 生成4个随机数 70 createdCode () { 71 const len = 4 72 const codeList = [] 73 const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789' 74 const charsLen = chars.length 75 for (let i = 0; i < len; i++) { 76 codeList.push(chars.charAt(Math.floor(Math.random() * charsLen))) 77 } 78 this.identifyCode = codeList.join('') 79 this.$emit('getIdentifyCode', this.identifyCode.toLowerCase()) 80 this.drawPic() 81 }, 82 83 // 生成一个随机数 84 randomNum (min, max) { 85 return Math.floor(Math.random() * (max - min) + min) 86 }, 87 // 生成一个随机的颜色 88 randomColor (min, max) { 89 const r = this.randomNum(min, max) 90 const g = this.randomNum(min, max) 91 const b = this.randomNum(min, max) 92 return 'rgb(' + r + ',' + g + ',' + b + ')' 93 }, 94 95 drawPic () { 96 const canvas = document.getElementById('s-canvas') 97 const ctx = canvas.getContext('2d') 98 ctx.textBaseline = 'bottom' 99 // 绘制背景 100 ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax) 101 ctx.fillRect(0, 0, this.contentWidth, this.contentHeight) 102 // 绘制文字 103 for (let i = 0; i < this.identifyCode.length; i++) { 104 this.drawText(ctx, this.identifyCode[i], i) 105 } 106 this.drawLine(ctx) 107 this.drawDot(ctx) 108 }, 109 110 drawText (ctx, txt, i) { 111 ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax) 112 ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' 113 const x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1)) 114 const y = this.randomNum(this.fontSizeMax, this.contentHeight - 5) 115 var deg = this.randomNum(-45, 45) 116 // 修改坐标原点和旋转角度 117 ctx.translate(x, y) 118 ctx.rotate(deg * Math.PI / 180) 119 ctx.fillText(txt, 0, 0) 120 // 恢复坐标原点和旋转角度 121 ctx.rotate(-deg * Math.PI / 180) 122 ctx.translate(-x, -y) 123 }, 124 125 // 绘制干扰线 126 drawLine (ctx) { 127 for (let i = 0; i < 5; i++) { 128 ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax) 129 ctx.beginPath() 130 ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight)) 131 ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight)) 132 ctx.stroke() 133 } 134 }, 135 136 // 绘制干扰点 137 drawDot (ctx) { 138 for (let i = 0; i < 80; i++) { 139 ctx.fillStyle = this.randomColor(0, 255) 140 ctx.beginPath() 141 ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI) 142 ctx.fill() 143 } 144 } 145 } 146 }) 147 </script> 148 <style scoped> 149 .s-canvas { 150 height: 38px; 151 cursor: pointer; 152 } 153 .s-canvas canvas{ 154 margin-top: 1px; 155 margin-left: 8px; 156 } 157 </style>