vue實現二維碼生成器和解碼器
1.生成基本二維碼:根據輸入的value生成二維碼。
2.可定制尺寸:通過size調整大小。
3.顏色和背景色:設置二維碼顏色和背景。
4.靜區(quiet zone)支持:通過quietZone調整周圍的空白區域。
5.錯誤糾正級別:ecl參數控制容錯級別。
6.漸變效果:啟用線性漸變,可以自定義方向和顏色。
7.Logo嵌入:在二維碼中間添加logo,可調整大小、邊距、背景色和圓角。
8.錯誤處理:生成失敗時顯示錯誤信息。
9.響應式更新:當props變化時自動重新生成二維碼。
10.視圖框調整:根據靜區計算viewBox,確保正確顯示。
效果圖:
step1: 添加依賴 npm install qrcode @types/qrcode
step2:核心組件 實現二維碼
C:\Users\wangrusheng\PycharmProjects\untitled3\src\views\QrCode.vue
<template><!-- SVG 容器 --><svgv-if="!error":viewBox="viewBox":width="size":height="size"><!-- 背景 --><rect:x="-quietZone":y="-quietZone":width="size + quietZone * 2":height="size + quietZone * 2":fill="backgroundColor"/><!-- 漸變定義 --><defs v-if="enableLinearGradient"><linearGradientid="grad":x1="gradientDirection[0]":y1="gradientDirection[1]":x2="gradientDirection[2]":y2="gradientDirection[3]"><stop offset="0" :stop-color="linearGradient[0]" stop-opacity="1"/><stop offset="1" :stop-color="linearGradient[1]" stop-opacity="1"/></linearGradient></defs><!-- 二維碼路徑 --><path:d="path"stroke-linecap="butt":stroke="enableLinearGradient ? 'url(#grad)' : color":stroke-width="cellSize"/><!-- Logo 容器 --><svgv-if="logo":x="(size - logoSize - logoMargin * 2) / 2":y="(size - logoSize - logoMargin * 2) / 2"><!-- Logo 背景 --><rect:width="logoSize + logoMargin * 2":height="logoSize + logoMargin * 2":fill="logoBackgroundColor":rx="logoBorderRadius + (logoMargin / logoSize) * logoBorderRadius":ry="logoBorderRadius + (logoMargin / logoSize) * logoBorderRadius"/><!-- Logo 圖片 --><image:x="logoMargin":y="logoMargin":width="logoSize":height="logoSize":href="logo"preserveAspectRatio="xMidYMid slice":rx="logoBorderRadius":ry="logoBorderRadius"/></svg></svg><!-- 錯誤顯示 --><div v-if="error" class="error">{{ error.message }}</div>
</template><script setup lang="ts">
import { ref, watchEffect, computed } from 'vue'
import QRCode from 'qrcode'// Props 定義
const props = defineProps({value: { type: String, default: 'this is a QR code' },size: { type: Number, default: 100 },color: { type: String, default: 'black' },backgroundColor: { type: String, default: 'white' },logo: { type: String, default: undefined },logoSize: { type: Number, default: 100 * 0.2 }, // 默認基于 size 計算logoBackgroundColor: { type: String, default: 'transparent' },logoMargin: { type: Number, default: 2 },logoBorderRadius: { type: Number, default: 0 },quietZone: { type: Number, default: 0 },enableLinearGradient: { type: Boolean, default: false },gradientDirection: {type: Array as () => string[],default: () => ['0%', '0%', '100%', '100%']},linearGradient: {type: Array as () => string[],default: () => ['rgb(255,0,0)', 'rgb(0,255,255)']},ecl: { type: String as () => 'L'|'M'|'Q'|'H', default: 'M' }
})// 響應式數據
const path = ref('')
const cellSize = ref(0)
const error = ref<Error | null>(null)// 生成二維碼矩陣
const genMatrix = (value: string, errorCorrectionLevel: string): boolean[][] => {const arr = Array.prototype.slice.call(QRCode.create(value, { errorCorrectionLevel }).modules.data, 0)const sqrt = Math.sqrt(arr.length)return arr.reduce((rows: boolean[][], key: boolean, index: number) => {(index % sqrt === 0) ? rows.push([key]) : rows[rows.length - 1].push(key)return rows}, [])
}// 轉換矩陣為 SVG 路徑
const transformMatrixIntoPath = (matrix: boolean[][], size: number) => {const cellSize = size / matrix.lengthlet path = ''matrix.forEach((row, i) => {let needDraw = falserow.forEach((column, j) => {if (column) {if (!needDraw) {path += `M${cellSize * j} ${cellSize / 2 + cellSize * i} `needDraw = true}if (needDraw && j === matrix.length - 1) {path += `L${cellSize * (j + 1)} ${cellSize / 2 + cellSize * i} `}} else {if (needDraw) {path += `L${cellSize * j} ${cellSize / 2 + cellSize * i} `needDraw = false}}})})return { cellSize, path }
}// 計算 viewBox
const viewBox = computed(() => [-props.quietZone,-props.quietZone,props.size + props.quietZone * 2,props.size + props.quietZone * 2
].join(' '))// 監聽 props 變化
watchEffect(() => {try {const matrix = genMatrix(props.value, props.ecl)const result = transformMatrixIntoPath(matrix, props.size)path.value = result.pathcellSize.value = result.cellSizeerror.value = null} catch (err) {error.value = err instanceof Error ? err : new Error('QR Code generation failed')}
})
</script><style scoped>
.error {color: red;border: 1px solid red;padding: 1rem;
}
</style>
step3: 調用二維碼組件
C:\Users\wangrusheng\PycharmProjects\untitled3\src\views\ImgCode.vue
<template><QrCode:value="qrCodeValue":size="200"color="#333"logo="/logo.png":logo-size="40"logo-background-color="white":enable-linear-gradient="true"/>
</template><script setup>
import QrCode from './QrCode.vue'
import { ref } from 'vue'
// 圖片資源存放在 C:\Users\wangrusheng\PycharmProjects\untitled3\public\logo.png
// JSON.stringify() 是 JavaScript 中用于將對象或值轉換為 JSON 格式字符串的核心方法,
//value="你們好,這里是二維碼識別器,很高興認識你們"
const qrCodeValue = ref(JSON.stringify({"data": [{"case_id": 3,"category_id": 4,"title": "as","description": "ad","price": 4500.0,"client_id": 5,"lawyer_id": 6,"status": "pending","created_at": "2025-03-21T06:11:59","updated_at": "2025-03-21T06:11:59","category_name": "af"},{"case_id": 8,"category_id": 8,"title": "bs","description": "bd","price": 6000.0,"client_id": 5,"lawyer_id": 6,"status": "in_progress","created_at": "2025-03-21T06:11:59","updated_at": "2025-03-21T06:11:59","category_name": "bf"}]
}))
</script>
step4:路由
C:\Users\wangrusheng\PycharmProjects\untitled3\src\router\index.js
import ImgCode from '../views/ImgCode.vue'
{ path: '/imgcode', name: 'imgcode', component: ImgCode },C:\Users\wangrusheng\PycharmProjects\untitled3\src\App.vue
<router-link to="/imgcode" active-class="active-link">二維碼</router-link>
///我是分割線
解碼部分
step101:安裝依賴 pip install pyzbar Pillow,你去網站上,隨便找個二維碼生成器,然后將生成的二維碼保存本地
step102:解析C:\Users\wangrusheng\PycharmProjects\FastAPIProject1\hello.py
from pyzbar.pyzbar import decode
from PIL import Image# 二維碼圖片路徑 C:\Users\wangrusheng\Downloads
old_file = r'C:\Users\wangrusheng\Downloads\logoz.png'try:# 打開圖片文件with Image.open(old_file) as img:# 解析二維碼decoded_objects = decode(img)if not decoded_objects:print("未檢測到二維碼內容。")else:for obj in decoded_objects:# 解碼數據(假設內容為UTF-8文本)data = obj.data.decode('utf-8')print("解析結果:", data)except FileNotFoundError:print(f"錯誤:文件 '{old_file}' 不存在。")
except Exception as e:print(f"解析時發生錯誤: {str(e)}")
step103:運行
(.venv) PS C:\Users\wangrusheng\PycharmProjects\FastAPIProject1> python hello.py
解析結果: 能不能點點贊 點點關注,我謝謝大家
(.venv) PS C:\Users\wangrusheng\PycharmProjects\FastAPIProject1>
end