前言
其实吧,QrcodeVue 配合html2canvas 可以完美实现上述功能,只是考虑到我们只是把QrcodeVue生成的svg 转化为图片并下载不用去引入三方库实现,而是只用几十行代码就能搞定,节省2M的html2canvas打包空间。
废话不多说,直接上代码。代码中调用的方法newDownLoad() 内容即为实现 将svg 转化为 canvas 然后下载为图片
代码
<template>
<div v-if="visible" class="qr-code-component sys-flex-column sys-flex-center">
<div class="qr-code-container sys-flex-column">
<div class="close-icon-container sys-flex-row sys-flex-center" @click="close">
<i class="iconfont icon-guanbi1"></i>
</div>
<!--<div class="qr-code-header">-->
<!--<h3>题目二维码</h3>-->
<!--</div>-->
<div class="qr-code-body sys-flex-column sys-flex-center flex1">
<div style="border: 1px solid #eeeeee;">
<div :id="shotDomId" class="screen-shot sys-flex-column sys-flex-center">
<qrcode-vue id="my-practise-qrcode" :value="qrcodeUrl" :size="200" renderAs="svg" background="#fff" :foreground="color" level="M">
</qrcode-vue>
<div :style="{color: color}" v-if="qrcodeTitle" class="practise-id">{{qrcodeTitle}}</div>
</div>
</div>
</div>
<div class="qr-code-footer sys-flex-row sys-flex-center">
<el-button type="primary" class="btn" @click="newDownLoad(qrcodeTitle)">下载图片</el-button>
</div>
</div>
</div>
</template>
<script>
import QrcodeVue from 'qrcode.vue'
import logo from './logo'
export default {
name: 'index',
components: { QrcodeVue, logo },
props: {
qrcodeVal: {
type: [String, Number],
required: true
},
qrcodeTitle: {
type: [String, Number],
required: false
},
visible: {
type: Boolean,
required: true
},
color: {
type: String,
required: false,
default: '#000000'
}
},
data() {
return {
shotDomId: ''
}
},
methods: {
close() {
this.$emit('close', false)
},
newDownLoad(name) {
const qrcodeElement = document.getElementById('my-practise-qrcode');
// 获取 SVG 子元素
const svg = qrcodeElement.querySelector('svg')
const serializer = new XMLSerializer();
const svgData = serializer.serializeToString(svg); // 将SVG数据转换为Data URL
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(svgBlob); // 创建一个Image对象
const img = new Image();
img.onload = () => { // 获取Canvas元素
const wid = svg.width.baseVal.value
const hei = svg.height.baseVal.value
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d');
const padding = 10; // 增加的白色间隙
canvas.width = wid + 2 * padding;
canvas.height = hei + 2 * padding + 20; // 增加底部文字的高度
// 绘制白色背景
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制二维码图片
ctx.drawImage(img, padding, padding, wid, hei);
// 绘制文本
const text = name;
const fontSize = 16;
const fontWeight = 'bold';
ctx.font = `${fontWeight} ${fontSize}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.fillStyle = 'black'; // 文本颜色
const textX = canvas.width / 2;
const textY = canvas.height - 25; // 文本位置在底部中央
ctx.fillText(text, textX, textY);
// 将 canvas 转换为 Data URL
const dataURL = canvas.toDataURL('image/png');
const a = document.createElement('a');
a.href = dataURL;
a.download = `${name}.png`;
a.target = '_blank';
a.click();
URL.revokeObjectURL(url);
}
img.src = url;
}
},
beforeDestroy() {
let html = document.getElementsByTagName('html')[0]
html.style.overflow = ''
},
watch: {
visible: {
handler(N, O) {
let html = document.getElementsByTagName('html')[0]
html.style.overflow = N ? 'hidden' : ''
this.shotDomId = 'screen-shot-dom-' + new Date().getTime()
},
immediate: true
}
},
computed: {
qrcodeUrl() {
const QRurl = 'https://xxx.xxxx.com'
return QRurl
}
}
}
</script>
<style lang="scss">
.qr-code-component {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
z-index: 9999;
.qr-code-container {
background: #ffffff;
width: 332px;
height: 424px;
border-radius: 20px;
position: relative;
.close-icon-container {
width: 26px;
height: 26px;
overflow: hidden;
border: 2px solid #ffffff;
border-radius: 50%;
background: #c8c9ca;
color: #ffffff;
position: absolute;
top: -30px;
right: -30px;
cursor: pointer;
i {
margin: 0 !important;
font-size: 18px;
}
}
.qr-code-header {
height: 40px;
background: #efefef;
line-height: 40px;
padding: 0 20px;
border-bottom: 1px solid #cccccc;
}
.qr-code-body {
/*background: red;*/
padding-top: 40px;
.screen-shot {
padding: 20px 20px 10px 20px;
.practise-id {
font-size: 16px;
font-weight: bolder;
margin-top: 10px;
}
}
}
.qr-code-footer {
height: 120px;
.btn {
height: 41px;
width: 120px;
}
}
}
.qrcode-icon {
position: absolute;
width: 45px;
height: 60px;
background: #f7f7f7;
left: 143px;
top: 131px;
}
}
</style>