Vue3+TypeScript實(shí)現(xiàn)二維碼生成組件
簡(jiǎn)介
在 Web 應(yīng)用中,生成二維碼是常見(jiàn)的需求。本文介紹如何用 Vue3 和 TypeScript 開(kāi)發(fā)一個(gè)二維碼生成組件,支持生成圖片或 canvas 形式的二維碼,并提供豐富的配置選項(xiàng)。
技術(shù)棧
- Vue3
- TypeScript
- Element Plus
- qrcode
- 圖片預(yù)覽組件
組件功能
- 支持生成圖片和 canvas 形式的二維碼: 可以根據(jù)需求選擇生成圖片或 canvas 形式的二維碼。
- 自定義配置選項(xiàng): 提供豐富的配置選項(xiàng),如二維碼大小、圖標(biāo)大小、二維碼顏色、容錯(cuò)級(jí)別等。
- 支持lgog二維碼: canvas 形式下支持配置logo二維碼。
- 二維碼預(yù)覽: 圖片形式下支持二維碼預(yù)覽功能。
- 下載: 組件內(nèi)提供下載二維碼到本地的方法。
組件代碼
生成uuid方法,防止在 canvas 形式下同一頁(yè)面生成多個(gè)二維碼時(shí)導(dǎo)致 canvasId 重復(fù)
/**
* @description 生成唯一 uuid
* @return string
*/
export function generateUUID() {
if (typeof crypto === "object") {
if (typeof crypto.randomUUID === "function") {
return crypto.randomUUID();
}
if (typeof crypto.getRandomValues === "function" && typeof Uint8Array === "function") {
const callback = (c: any) => {
const num = Number(c);
return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(16);
};
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, callback);
}
}
let timestamp = new Date().getTime();
let performanceNow = (typeof performance !== "undefined" && performance.now && performance.now() * 1000) || 0;
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
let random = Math.random() * 16;
if (timestamp > 0) {
random = (timestamp + random) % 16 | 0;
timestamp = Math.floor(timestamp / 16);
} else {
random = (performanceNow + random) % 16 | 0;
performanceNow = Math.floor(performanceNow / 16);
}
return (c === "x" ? random : (random & 0x3) | 0x8).toString(16);
});
}
以下是組件的核心代碼:
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import QRCode, { type QRCodeRenderersOptions } from "qrcode";
import { generateUUID } from "@/utils/util";
interface QRCodeProps {
type?: "canvas" | "img"; // 二維碼類(lèi)型 ==> 默認(rèn)img, img 支持預(yù)覽,canvas支持logo
size?: number; // 二維碼大小 ==> 默認(rèn)200
iconSize?: number; // 二維碼圖標(biāo)大小 ==> 默認(rèn)40
content: string; // 二維碼內(nèi)容 ==> 必填
logo?: string; // 二維碼logo ==> 默認(rèn)無(wú)
options?: QRCodeRenderersOptions; // 二維碼配置 ==> 默認(rèn)無(wú)
errorLevel?: "L" | "M" | "Q" | "H"; // 二維碼容錯(cuò)級(jí)別 ==> 默認(rèn)H
}
// 接收父組件參數(shù)并設(shè)置默認(rèn)值
const props = withDefaults(defineProps<QRCodeProps>(), {
type: "img",
size: 200,
iconSize: 40,
errorLevel: "H"
});
const qrCodeUrl = ref<string>("");
const canvasId = ref("canvas" + generateUUID());
const loading = ref(true);
const QRCodeStyle = computed(() => {
return {
width: props.size + "px",
height: props.size + "px"
};
});
// 生成二維碼
const initQRCode = async () => {
if (props.type === "canvas") {
const canvasRef: any = await QRCode.toCanvas(document.getElementById(canvasId.value), props.content, {
width: props.size,
margin: 2,
errorCorrectionLevel: props.errorLevel,
...props.options
});
if (props.logo) {
const ctx = canvasRef.getContext("2d");
const iconBgW = props.iconSize + 5;
const iconBgH = props.iconSize + 5;
const iconBgX = (canvasRef.width - iconBgW) / 2;
const iconBgY = (canvasRef.width - iconBgH) / 2;
ctx.fillStyle = "#fff";
ctx.fillRect(iconBgX, iconBgY, iconBgW, iconBgH);
// logo
const iconX = (canvasRef.width - props.iconSize) / 2;
const iconY = (canvasRef.width - props.iconSize) / 2;
const image = new Image();
image.crossOrigin = "Anonymous"; // 設(shè)置圖片的跨域?qū)傩?
image.onload = () => {
ctx.drawImage(image, iconX, iconY, props.iconSize, props.iconSize);
qrCodeUrl.value = canvasRef.toDataURL();
};
image.src = props.logo;
} else {
qrCodeUrl.value = canvasRef.toDataURL();
}
loading.value = false;
} else {
const url = await QRCode.toDataURL(props.content, {
width: props.size,
margin: 2,
errorCorrectionLevel: props.errorLevel,
...props.options
});
qrCodeUrl.value = url;
loading.value = false;
}
};
// 下載二維碼
const downLoadQRCode = (fileName: string = generateUUID(), fileType: string = ".png") => {
const exportFile = document.createElement("a");
exportFile.style.display = "none";
exportFile.download = `${fileName}${fileType}`;
exportFile.href = qrCodeUrl.value;
document.body.appendChild(exportFile);
exportFile.click();
// 去除下載對(duì) url 的影響
document.body.removeChild(exportFile);
};
onMounted(() => {
initQRCode();
});
defineExpose({
downLoadQRCode
});
</script>
<template>
<div :style="QRCodeStyle" overflow-hidden rounded-lg border border-slate-300 border-solid v-loading="loading">
<ImagePreview :width="QRCodeStyle.width" :height="QRCodeStyle.height" v-if="type === 'img'" :image-url="qrCodeUrl" />
<canvas v-else :style="QRCodeStyle" :id="canvasId"></canvas>
</div>
</template>
<style lang="scss" scoped></style>
總結(jié)
通過(guò)結(jié)合 Vue3、TypeScript 和其他現(xiàn)代前端技術(shù),我們打造了一個(gè)功能豐富的二維碼生成組件。該組件支持多種形式展示,包括圖片和 canvas 二維碼。用戶(hù)可以輕松放大預(yù)覽圖片二維碼,或者通過(guò) canvas 添加自定義 logo。除此之外,在組件內(nèi)還提供了便捷的下載功能。這一解決方案為開(kāi)發(fā)者在 Web 應(yīng)用中集成二維碼生成功能提供了便捷而強(qiáng)大的工具。
希望這篇文章能夠幫助你更好地了解如何使用 Vue3 和 TypeScript 實(shí)現(xiàn) 生成二維碼功能!如果你有任何問(wèn)題或建議,請(qǐng)隨時(shí)提出。
以上就是Vue3+TypeScript實(shí)現(xiàn)二維碼生成組件的詳細(xì)內(nèi)容,更多關(guān)于Vue3+TypeScript二維碼的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue.js實(shí)現(xiàn)刷新當(dāng)前頁(yè)面的方法教程
這篇文章主要給大家介紹了關(guān)于vue.js實(shí)現(xiàn)刷新當(dāng)前頁(yè)面的方法教程,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編一起來(lái)學(xué)習(xí)學(xué)習(xí)吧。2017-07-07
分享一個(gè)精簡(jiǎn)的vue.js 圖片lazyload插件實(shí)例
本篇文章主要介紹了分享一個(gè)精簡(jiǎn)的vue.js 圖片lazyload插件實(shí)例。非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-03-03
vue中$nexttick,$set,$forceupdate的區(qū)別
本文主要介紹了vue中$nexttick,$set,$forceupdate的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Vue2實(shí)現(xiàn)圖片的拖拽,縮放和旋轉(zhuǎn)效果的示例代碼
這篇文章主要為大家介紹了如何基于vue2?實(shí)現(xiàn)圖片的拖拽、旋轉(zhuǎn)、鼠標(biāo)滾動(dòng)放大縮小等功能。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-11-11
vue實(shí)現(xiàn)動(dòng)態(tài)路由的方法及路由原理解析
這篇文章主要介紹了路由原理及vue實(shí)現(xiàn)動(dòng)態(tài)路由,Vue Router 提供了豐富的 API,可以輕松地實(shí)現(xiàn)路由功能,并支持路由參數(shù)、查詢(xún)參數(shù)、命名路由、嵌套路由等功能,可以滿(mǎn)足不同應(yīng)用程序的需求,需要的朋友可以參考下2023-06-06
Vue使用el-table實(shí)現(xiàn)表格跨頁(yè)多選
在我們?nèi)粘m?xiàng)目開(kāi)發(fā)中,經(jīng)常會(huì)有表格跨頁(yè)多選的需求,接下來(lái)讓我們用?el-table示例一步步來(lái)實(shí)現(xiàn)這個(gè)需求,文中有詳細(xì)的代碼講解,對(duì)我們的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-08-08
詳解vuex中mapState,mapGetters,mapMutations,mapActions的作用
這篇文章主要介紹了vuex中mapState,mapGetters,mapMutations,mapActions的作用,需要的朋友可以參考下2018-04-04

