⭐前言
在vue項目中,登錄界面必不可少。簡單項目里,驗證碼通常由數字字母構成。一般有兩種產生方式:前端,后端。后端生成,前端直接調用接口,將返回的url放入a標簽即可。而前端生成,則大多用canvas畫布實現,如何讓驗證碼隨屏幕大小變化,還能保持原樣不失真,這就是我們要實現的功能。當然,在創建vue項目時,我們必須得克服跨域問題。No ' Access-Control-Allow-Origin'的解決方案,在文章最后。若有錯誤和建議,請積極指正!
⭐canvas 生成驗證碼 (vue)
按照需求,一步步實現驗證碼生成。(源碼貼在后面)
下面,進入正題。
組件需要什么?
首先,我們自己注冊一個組件 Identify.vue
,用來實現驗證碼的生成。
第一步, 我們要明確,這個組件需要什么?
顯然,我們需要一個畫布,在畫布上進行繪制,生成驗證碼就好。
自然而然,<canvas></canvas>
就布局上去了。
<template>
<div class="canvas">
<canvas id="canvas" class="yanzheng1"></canvas>
</div>
</template>
再者,我們需定義組件屬性
props: {
identifyCode: { // 默認注冊碼
type: String,
default: '1234'
},
fontSizeMin: { // 字體最小值
type: Number,
default: 130
},
fontSizeMax: { // 字體最大值
type: Number,
default: 140
}
}
組件的實現
接下來,我們可以進行繪制驗證碼。內容包括如下:
1、隨機數(驗證碼內容:一般為數字字母組合)
2、隨機顏色 (rgb實現)
3、干擾線
4、干擾點
隨機數
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
隨機色
randomColor (min, max) {
const r = this.randomNum(min, max)
const g = this.randomNum(min, max)
const b = this.randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
},
干擾線
drawLine (ctx) {
const canvas = document.getElementById('canvas')
for (let j = 0; j < 4; j++) {
ctx.strokeStyle = this.randomColor(100, 200)
ctx.beginPath()
ctx.moveTo(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height))
ctx.lineTo(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height))
// lineWidth 控制線的粗細
ctx.lineWidth = 3
ctx.stroke()
}
},
干擾點
drawDot (ctx) {
const canvas = document.getElementById('canvas')
for (let k = 0; k < 30; k++) {
ctx.fillStyle = this.randomColor(0, 255)
ctx.beginPath()
// 可以改變 3 來實現改變干擾點的大小
ctx.arc(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height), 3, 0, 2 * Math.PI)
ctx.fill()
}
}
繪制驗證碼
drawPic () {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.textBaseline = 'bottom'
// console.log(canvas.width)
// 繪制背景(顏色)
ctx.fillStyle = '#e6ecfd'
ctx.fillRect(0, 0, canvas.width, canvas.height)
// 繪制文字
for (let i = 0; i < this.identifyCode.length; i++) {
this.drawText(ctx, this.identifyCode[i], i)
}
this.drawLine(ctx)
this.drawDot(ctx)
},
drawText (ctx, txt, i) {
const canvas = document.getElementById('canvas')
ctx.fillStyle = this.randomColor(50, 160) // 隨機生成字體顏色
ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' // 隨機生成字體大小
// x,y控制生成字體在畫布上分布的位置。如下的0.5/1,可根據實際情況進行增減。
const x = (i + 0.5 ) * (canvas.width / (this.identifyCode.length + 1))
const y = this.randomNum(this.fontSizeMax, canvas.height - 5)
var deg = this.randomNum(-30, 30)
// 修改坐標原點和旋轉角度
ctx.translate(x, y)
ctx.rotate(deg * Math.PI / 180)
ctx.fillText(txt, 0, 0)
// 恢復坐標原點和旋轉角度
ctx.rotate(-deg * Math.PI / 180)
ctx.translate(-x, -y)
},
注意:
const canvas = document.getElementById('canvas') // canvas.width是為了獲取到畫布的寬度,實現適配。高度亦是如此。
組件源碼
原理搞懂,直接上手。新建一個vue文件。
Identify.vue
代碼如下:
<template>
<div class="canvas">
<canvas id="canvas" class="yanzheng1"></canvas>
</div>
</template>
<script>
export default {
name: 'Identify',
props: {
identifyCode: { // 默認注冊碼
type: String,
default: '1234'
},
fontSizeMin: { // 字體最小值
type: Number,
default: 130
},
fontSizeMax: { // 字體最大值
type: Number,
default: 140
}
},
methods: {
// 生成一個隨機數
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
// 生成一個隨機的顏色
randomColor (min, max) {
const r = this.randomNum(min, max)
const g = this.randomNum(min, max)
const b = this.randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
},
drawPic () {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.textBaseline = 'bottom'
// console.log(canvas.width)
// 繪制背景
ctx.fillStyle = '#e6ecfd'
ctx.fillRect(0, 0, canvas.width, canvas.height)
// 繪制文字
for (let i = 0; i < this.identifyCode.length; i++) {
this.drawText(ctx, this.identifyCode[i], i)
}
this.drawLine(ctx)
this.drawDot(ctx)
},
drawText (ctx, txt, i) {
const canvas = document.getElementById('canvas')
ctx.fillStyle = this.randomColor(50, 160) // 隨機生成字體顏色
ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' // 隨機生成字體大小
const x = (i + 0.5 ) * (canvas.width / (this.identifyCode.length + 1))
const y = this.randomNum(this.fontSizeMax, canvas.height - 5)
var deg = this.randomNum(-30, 30)
// 修改坐標原點和旋轉角度
ctx.translate(x, y)
ctx.rotate(deg * Math.PI / 180)
ctx.fillText(txt, 0, 0)
// 恢復坐標原點和旋轉角度
ctx.rotate(-deg * Math.PI / 180)
ctx.translate(-x, -y)
},
drawLine (ctx) {
// 繪制干擾線
const canvas = document.getElementById('canvas')
for (let j = 0; j < 4; j++) {
ctx.strokeStyle = this.randomColor(100, 200)
ctx.beginPath()
ctx.moveTo(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height))
ctx.lineTo(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height))
ctx.lineWidth = 3
ctx.stroke()
}
},
drawDot (ctx) {
// 繪制干擾點
const canvas = document.getElementById('canvas')
for (let k = 0; k < 30; k++) {
ctx.fillStyle = this.randomColor(0, 255)
ctx.beginPath()
ctx.arc(this.randomNum(0, canvas.width), this.randomNum(0, canvas.height), 3, 0, 2 * Math.PI)
ctx.fill()
}
}
},
watch: {
identifyCode () {
this.drawPic()
}
},
mounted () {
this.drawPic()
}
}
</script>
<style scoped>
.yanzheng1{
width: 100px;
height: 34px;
}
</style>
之后,在要引入的頁面,引用。
引用驗證碼.vue
這里用的是 element UI
elementUI官網
<el-form-item prop="code">
<el-input @keyup.enter.native="checkCode" type="text" v-model="code" placeholder=" - - - -">
<template slot="suffix">
<div class="yanzheng" @click="refreshCode">
<!-- Identify就是注冊組件-->
<Identify class="yanzheng1" :identifyCode="identifyCode"></Identify>
</div>
</template>
</el-input>
</el-form-item>
<!-- @keyup.enter.native 實現輸入完,按回車執行checkCode函數,或者按鈕實現-->
<script>
import Identify from '../components/Identify.vue'
export default {
components: {
Identify
},
data () {
return {
identifyCodes: '1234567890abcdefjhijk1234567890linopqrsduvwxyz', // 驗證碼組成元素
identifyCode: '', // 驗證碼生成結果
code:'', // 驗證碼輸入內容
}
},
mounted () {
// 初始化驗證碼
this.identifyCode = ''
this.makeCode(this.identifyCodes, 4)
},
methods:{
// 重置驗證碼
refreshCode () {
this.identifyCode = ''
this.makeCode(this.identifyCodes, 4)
},
makeCode (o, l) {
// o代表隨機數元素集合,l代表驗證碼位數(現在為4位驗證碼)
for (let i = 0; i < l; i++) {
this.identifyCode += this.identifyCodes[this.randomNum(0, this.identifyCodes.length)]
}
},
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
checkCode(){
if (this.code.toLowerCase() !== this.identifyCode.toLowerCase()) {
this.$message.error('請填寫正確驗證碼')
this.refreshCode()
}
else {
this.$message.success('驗證成功!')
// 執行功能函數
}
}
}
}
</script>
<style scoped>
.yanzheng{
width: 100px;
height: 34px;
text-align: center;
margin: 5px 30px;
border: 2px solid #009199;
}
.yanzheng1{
width: 100px;
height: 34px;
}
</style>
css樣式,可自行調整。實現效果如下:
⭐vue自適應,可采用rem布局
安裝postcss-px2rem以及px2rem-loader
npm install postcss-px2rem px2rem-loader --save
創建 rem.js
文件
可在src目錄下創建utils文件夾,放入其中(/src/utils/rem.js)
// rem等比適配配置文件
// 基准大小
const baseSize = 16
// 設置 rem 函數
function setRem () {
if (document.documentElement.clientWidth < 768) {
// 當前頁面寬度相對於750寬的縮放比例。
document.documentElement.style.fontSize = baseSize *(document.documentElement.clientWidth/ 750 - 0.36) + 'px'
}
else {
// 當前頁面寬度相對於1920寬的縮放比例。
const scale = document.documentElement.clientWidth / 1920
// 設置頁面根節點字體大小
document.documentElement.style.fontSize = baseSize * Math.min(scale, 1.7) + 'px'
}
}
// 初始化
setRem()
// 改變窗口大小時重新設置 rem
window.onresize = function () {
setRem()
}
在main.js中引入
import '../src/util/rem'
最后,在 vue.config.js
中配置插件
// 引入等比適配插件
const px2rem = require('postcss-px2rem')
// 配置基本大小
const postcss = px2rem({
// 基准大小 baseSize,需要和rem.js中相同
remUnit: 16
})
// 使用等比適配插件
module.exports = {
lintOnSave: true,
css: {
loaderOptions: {
postcss: {
plugins: [
postcss
]
}
}
}
}
不要忘記重啟!!重啟方可生效!
⭐vue跨域問題,No ' Access-Control-Allow-Origin'
在開始vue項目構建之前的必經之路,就是避免跨域問題。
直接上手:
vue.config.js配置
創建好vue工程后,找到 vue.config.js
文件,雙擊點擊進入項目即可(與src目錄同級)
若沒有該配置文件,則新建 vue.config.js
文件,與src目錄同級。
module.exports = {
devServer: {
host: '127.0.0.1', // 本地
open: true,
port: 8082, // 本地開放端口
overlay: true,
headers: {
'Access-Control-Allow-Origin': '*'
},
hotOnly: false,
disableHostCheck: true,
proxy: {
'/api': {
target: 'https://xxx.xxx.xxx.xxx:8181', // 目標服務器,api請求地址(https和http要區分)
ws: true,
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
}
}
一般情況下,都會安裝 axios運行依賴 , 官網
npm install axios
main.js配置
在 main.js
中配置如下:
// 引入axios
import axios from 'axios'
Vue.prototype.$axios = axios
Vue.prototype.$http = axios
// 利用'/api'為基准地址,實現跨域。
axios.defaults.baseURL='/api'
Vue.config.productionTip = false
接口調用舉例
/test/all/
為接口請求
async getTestList () {
const { data: res } = await this.$http.get('/test/all/')
if (res.status !== 200) {
return this.$message.error(res.msg)
}
this.$message.success('成功!')
},
如下,出現api,即成功!
注意!!配置完記得重啟!!否則不生效!!
關於以上鏈接引用【侵權刪】