Vue3+TypeScript实现二维码生成组件

 更新时间:2024年04月28日 09:12:03   作者:下雨会打伞的前端  
在 Web 应用中,生成二维码是常见的需求,本文介绍如何用 Vue3 和 TypeScript 开发一个二维码生成组件,支持生成图片或 canvas 形式的二维码,并提供丰富的配置选项,感兴趣的小伙伴跟着小编一起来看看吧

简介

在 Web 应用中,生成二维码是常见的需求。本文介绍如何用 Vue3 和 TypeScript 开发一个二维码生成组件,支持生成图片或 canvas 形式的二维码,并提供丰富的配置选项。

技术栈

组件功能

  • 支持生成图片和 canvas 形式的二维码: 可以根据需求选择生成图片或 canvas 形式的二维码。
    • 自定义配置选项: 提供丰富的配置选项,如二维码大小、图标大小、二维码颜色、容错级别等。
  • 支持lgog二维码: canvas 形式下支持配置logo二维码。
  • 二维码预览: 图片形式下支持二维码预览功能。
  • 下载: 组件内提供下载二维码到本地的方法。

组件代码

生成uuid方法,防止在 canvas 形式下同一页面生成多个二维码时导致 canvasId 重复

/**
 * @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"; // 二维码类型 ==> 默认img, img 支持预览,canvas支持logo
	size?: number; // 二维码大小 ==> 默认200
	iconSize?: number; // 二维码图标大小 ==> 默认40
	content: string; // 二维码内容 ==> 必填
	logo?: string; // 二维码logo ==> 默认无
	options?: QRCodeRenderersOptions; // 二维码配置 ==> 默认无
	errorLevel?: "L" | "M" | "Q" | "H"; // 二维码容错级别 ==> 默认H
}

// 接收父组件参数并设置默认值
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"; // 设置图片的跨域属性
			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();
	// 去除下载对 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>

总结

通过结合 Vue3、TypeScript 和其他现代前端技术,我们打造了一个功能丰富的二维码生成组件。该组件支持多种形式展示,包括图片和 canvas 二维码。用户可以轻松放大预览图片二维码,或者通过 canvas 添加自定义 logo。除此之外,在组件内还提供了便捷的下载功能。这一解决方案为开发者在 Web 应用中集成二维码生成功能提供了便捷而强大的工具。

希望这篇文章能够帮助你更好地了解如何使用 Vue3 和 TypeScript 实现 生成二维码功能!如果你有任何问题或建议,请随时提出。

以上就是Vue3+TypeScript实现二维码生成组件的详细内容,更多关于Vue3+TypeScript二维码的资料请关注脚本之家其它相关文章!

相关文章

  • vue.js实现刷新当前页面的方法教程

    vue.js实现刷新当前页面的方法教程

    这篇文章主要给大家介绍了关于vue.js实现刷新当前页面的方法教程,文中给出了详细的示例代码供大家参考学习,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编一起来学习学习吧。
    2017-07-07
  • 分享一个精简的vue.js 图片lazyload插件实例

    分享一个精简的vue.js 图片lazyload插件实例

    本篇文章主要介绍了分享一个精简的vue.js 图片lazyload插件实例。非常具有实用价值,需要的朋友可以参考下。
    2017-03-03
  • vue中$nexttick,$set,$forceupdate的区别

    vue中$nexttick,$set,$forceupdate的区别

    本文主要介绍了vue中$nexttick,$set,$forceupdate的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Vue press 支持图片放大功能的实例代码

    Vue press 支持图片放大功能的实例代码

    这篇文章主要介绍了 Vue press 支持图片放大功能,本文通过代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • Vue2实现图片的拖拽,缩放和旋转效果的示例代码

    Vue2实现图片的拖拽,缩放和旋转效果的示例代码

    这篇文章主要为大家介绍了如何基于vue2 实现图片的拖拽、旋转、鼠标滚动放大缩小等功能。文中的示例代码讲解详细,感兴趣的小伙伴可以尝试一下
    2022-11-11
  • VUE安装使用教程详解

    VUE安装使用教程详解

    这篇文章主要介绍了安装使用VUE的教程,本文给大家提到了遇到的问题原因分析及解决方法,需要的朋友可以参考下
    2019-06-06
  • vue2安装tailwindcss的详细步骤

    vue2安装tailwindcss的详细步骤

    这篇文章主要介绍了vue2安装tailwindcss,本文分步骤结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • vue实现动态路由的方法及路由原理解析

    vue实现动态路由的方法及路由原理解析

    这篇文章主要介绍了路由原理及vue实现动态路由,Vue Router 提供了丰富的 API,可以轻松地实现路由功能,并支持路由参数、查询参数、命名路由、嵌套路由等功能,可以满足不同应用程序的需求,需要的朋友可以参考下
    2023-06-06
  • Vue使用el-table实现表格跨页多选

    Vue使用el-table实现表格跨页多选

    在我们日常项目开发中,经常会有表格跨页多选的需求,接下来让我们用 el-table示例一步步来实现这个需求,文中有详细的代码讲解,对我们的学习或工作有一定的帮助,需要的朋友可以参考下
    2023-08-08
  • 详解vuex中mapState,mapGetters,mapMutations,mapActions的作用

    详解vuex中mapState,mapGetters,mapMutations,mapActions的作用

    这篇文章主要介绍了vuex中mapState,mapGetters,mapMutations,mapActions的作用,需要的朋友可以参考下
    2018-04-04

最新评论