下载二维码功能

This commit is contained in:
1378012178@qq.com 2025-07-10 13:40:01 +08:00
parent 7cdfb9c7b6
commit e65263cffb
1 changed files with 223 additions and 205 deletions

View File

@ -1,215 +1,233 @@
<template>
<div ref="qrcodeRef">
<QRCodeVue3
:margin="margin"
:width="width"
:height="height"
:value="value"
:qrOptions="qrOptions"
:image="image"
:imageOptions="imageOptions"
:dotsOptions="dotsOptions"
:backgroundOptions="backgroundOptions"
:cornersSquareOptions="cornersSquareOptions"
:cornersDotOptions="cornersDotOptions"
:key="key"
/>
<div class="qrcode-container">
<!-- 直接绑定ref到QRCodeVue3组件 -->
<QRCodeVue3 ref="qrcodeInstance" render-as="canvas" :margin="margin" :width="width" :height="height" :value="value"
:qrOptions="qrOptions" :image="image" :imageOptions="imageOptions" :dotsOptions="dotsOptions"
:backgroundOptions="backgroundOptions" :cornersSquareOptions="cornersSquareOptions"
:cornersDotOptions="cornersDotOptions" :key="key" />
<button @click="downloadQRCode" :disabled="isDownloading" class="download-btn">
{{ isDownloading ? '生成中...' : '下载二维码' }}
</button>
</div>
</template>
<script lang="ts">
import {defineComponent, reactive, toRefs, PropType, ref} from "vue";
import QRCodeVue3 from "qrcode-vue3";
<script lang="ts" setup>
import { ref, reactive, toRefs, nextTick } from 'vue'
import QRCodeVue3 from 'qrcode-vue3'
import type { PropType } from 'vue'
export default defineComponent({
name: "Qrcode",
components: {
QRCodeVue3,
//
interface QRCodeExpose {
$el: HTMLCanvasElement
}
const props = defineProps({
key: {
type: String as PropType<string>,
default: "0",
},
props: {
//
key: {
type: String as PropType<string>,
default: 0,
},
//
width: {
type: String as PropType<string>,
default: 600,
},
//
height: {
type: String as PropType<string>,
default: 600,
},
//
value: {
type: String as PropType<string>,
default: "https://www.focusnu.com/devops",
},
//
margin: {
type: String as PropType<string>,
default:6,
},
//
backgroundColor: {
type: String as PropType<string>,
default: "white",
},
//logo
logo: {
type: String as PropType<string>,
default: '',
},
//
hideLogoDots: {
type: Boolean as PropType<boolean>,
default: true,
},
//logo
logoSize: {
type: String as PropType<string>,
default: 0.5,
},
//logo
logoMargin: {
type: String as PropType<string>,
default: 5,
},
//
dotsOptions: {
type: Object,
default: () => ({
type: "rounded", // square | dots | rounded | extra-rounded | classy | classy-rounded
color: "#0d2a56", //
// color
gradient: {
type: "radial", // linear线 | radial
rotation: 0,
colorStops: [
{
offset: 0,
color: "#21a3fa",
},
{
offset: 1,
color: "#0d2a56",
},
],
},
}),
},
/**
* 角落广场配置
*/
cornersSquareOptions: {
type: Object,
default: () => ({
type: "extra-rounded", // none | square | dot | extra-rounded
color: "#0d2a56",//
//
gradient: {
type: "linear",
rotation: 0,
colorStops: [
{
offset: 0,
color: "#0d2a56",
},
{
offset: 1,
color: "#21a3fa",
},
],
},
}),
},
/**
* 角落点配置
*/
cornersDotOptions: {
type: Object,
default: () => ({
type: "dot", // none | square | dot
color: "#0d2a56",//
//
gradient: {
type: "linear",
rotation: 0,
colorStops: [
{
offset: 0,
color: "#0d2a56",
},
{
offset: 1,
color: "#21a3fa",
},
],
},
}),
},
width: {
type: String as PropType<string>,
default: "600",
},
setup(props) {
console.log(props);
const qrcodeRef = ref(null);
const data = reactive({
key: props.key,//key
/**
* 基础配置
* https://qr-code-styling.com
*/
width: props.width, //
height: props.height, //
value: props.value, //
margin: props.margin, //
/**
* 背景配置
*/
backgroundOptions: {
//
color: props.backgroundColor,
},
/**
* 二维码配置
*/
qrOptions: {
typeNumber: "0", // 0 - 40
mode: "Byte", // Numeric | Alphanumeric | Byte | Kanji
errorCorrectionLevel: "Q", // L | M | Q | H 'L''M''Q''H'
},
/**
* 图像配置中心图片
*/
image: props.logo, //
imageOptions: {
hideBackgroundDots: props.hideLogoDots, //
imageSize: props.logoSize,
margin: props.logoMargin,
crossOrigin: "anonymous", // anonymous | use-credentials
},
/**
* 二维码点配置
*/
dotsOptions: props.dotsOptions,
/**
* 角落广场配置
*/
cornersSquareOptions: props.cornersSquareOptions,
/**
* 角落点配置
*/
cornersDotOptions: props.cornersDotOptions,
});
return {
...toRefs(data),
qrcodeRef
};
height: {
type: String as PropType<string>,
default: "600",
},
});
value: {
type: String as PropType<string>,
default: "https://www.focusnu.com/devops",
},
margin: {
type: String as PropType<string>,
default: "6",
},
backgroundColor: {
type: String as PropType<string>,
default: "white",
},
logo: {
type: String as PropType<string>,
default: '',
},
hideLogoDots: {
type: Boolean as PropType<boolean>,
default: true,
},
logoSize: {
type: String as PropType<string>,
default: "0.5",
},
logoMargin: {
type: String as PropType<string>,
default: "5",
},
dotsOptions: {
type: Object as PropType<{
type: string;
color: string;
gradient?: {
type: string;
rotation: number;
colorStops: Array<{ offset: number; color: string }>;
};
}>,
default: () => ({
type: "rounded",
color: "#0d2a56",
gradient: {
type: "radial",
rotation: 0,
colorStops: [
{ offset: 0, color: "#21a3fa" },
{ offset: 1, color: "#0d2a56" }
]
}
})
},
cornersSquareOptions: {
type: Object as PropType<{
type: string;
color: string;
gradient?: {
type: string;
rotation: number;
colorStops: Array<{ offset: number; color: string }>;
};
}>,
default: () => ({
type: "extra-rounded",
color: "#0d2a56",
gradient: {
type: "linear",
rotation: 0,
colorStops: [
{ offset: 0, color: "#0d2a56" },
{ offset: 1, color: "#21a3fa" }
]
}
})
},
cornersDotOptions: {
type: Object as PropType<{
type: string;
color: string;
gradient?: {
type: string;
rotation: number;
colorStops: Array<{ offset: number; color: string }>;
};
}>,
default: () => ({
type: "dot",
color: "#0d2a56",
gradient: {
type: "linear",
rotation: 0,
colorStops: [
{ offset: 0, color: "#0d2a56" },
{ offset: 1, color: "#21a3fa" }
]
}
})
}
})
const qrcodeInstance = ref<QRCodeExpose | null>(null)
const isDownloading = ref(false)
const data = reactive({
key: props.key,
width: props.width,
height: props.height,
value: props.value,
margin: props.margin,
backgroundOptions: {
color: props.backgroundColor,
},
qrOptions: {
typeNumber: "0",
mode: "Byte",
errorCorrectionLevel: "Q",
},
image: props.logo,
imageOptions: {
hideBackgroundDots: props.hideLogoDots,
imageSize: props.logoSize,
margin: props.logoMargin,
crossOrigin: "anonymous",
},
dotsOptions: props.dotsOptions,
cornersSquareOptions: props.cornersSquareOptions,
cornersDotOptions: props.cornersDotOptions,
})
const {
key,
width,
height,
value,
margin,
backgroundOptions,
qrOptions,
image,
imageOptions,
dotsOptions,
cornersSquareOptions,
cornersDotOptions
} = toRefs(data)
const downloadQRCode = async () => {
isDownloading.value = true
await nextTick() // DOM
// img
const imgEl = qrcodeInstance.value?.$el?.querySelector?.('img')
if (imgEl && imgEl.src) {
const imgSrc = imgEl.src
const link = document.createElement('a')
link.href = imgSrc
link.download = 'qrcode.png'
link.click()
} else {
console.error('未找到二维码 img 或 src 为空')
}
isDownloading.value = false
}
</script>
<style scoped>
.qrcode-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
}
.download-btn {
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
min-width: 120px;
}
.download-btn:hover {
background-color: #3aa876;
transform: translateY(-1px);
}
.download-btn:disabled {
background-color: #cccccc;
cursor: not-allowed;
transform: none;
}
</style>