下载二维码功能

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> <template>
<div ref="qrcodeRef"> <div class="qrcode-container">
<QRCodeVue3 <!-- 直接绑定ref到QRCodeVue3组件 -->
:margin="margin" <QRCodeVue3 ref="qrcodeInstance" render-as="canvas" :margin="margin" :width="width" :height="height" :value="value"
:width="width" :qrOptions="qrOptions" :image="image" :imageOptions="imageOptions" :dotsOptions="dotsOptions"
:height="height" :backgroundOptions="backgroundOptions" :cornersSquareOptions="cornersSquareOptions"
:value="value" :cornersDotOptions="cornersDotOptions" :key="key" />
:qrOptions="qrOptions" <button @click="downloadQRCode" :disabled="isDownloading" class="download-btn">
:image="image" {{ isDownloading ? '生成中...' : '下载二维码' }}
:imageOptions="imageOptions" </button>
:dotsOptions="dotsOptions"
:backgroundOptions="backgroundOptions"
:cornersSquareOptions="cornersSquareOptions"
:cornersDotOptions="cornersDotOptions"
:key="key"
/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import {defineComponent, reactive, toRefs, PropType, ref} from "vue"; import { ref, reactive, toRefs, nextTick } from 'vue'
import QRCodeVue3 from "qrcode-vue3"; import QRCodeVue3 from 'qrcode-vue3'
import type { PropType } from 'vue'
export default defineComponent({ //
name: "Qrcode", interface QRCodeExpose {
components: { $el: HTMLCanvasElement
QRCodeVue3, }
const props = defineProps({
key: {
type: String as PropType<string>,
default: "0",
}, },
props: { width: {
// type: String as PropType<string>,
key: { default: "600",
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",
},
],
},
}),
},
}, },
setup(props) { height: {
console.log(props); type: String as PropType<string>,
const qrcodeRef = ref(null); default: "600",
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
};
}, },
}); 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> </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>