196 lines
4.9 KiB
Vue
196 lines
4.9 KiB
Vue
<template>
|
||
<view style="position: fixed;z-index: -9999;">
|
||
<canvas :canvas-id="canvasID" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}"></canvas>
|
||
<view v-if="qrCode == ''">
|
||
<QRCode ref="qrcode" />
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import QRCode from "@/components/qr_code/qrcode.vue"
|
||
var _this;
|
||
export default {
|
||
name: 'canvas-images',
|
||
props: {
|
||
// canvasID 等同于 canvas-id
|
||
canvasID: {
|
||
Type: String,
|
||
default: 'shareCanvas'
|
||
},
|
||
canvasWidth: { // 画布宽度
|
||
Type: 'int',
|
||
default: 375
|
||
},
|
||
canvasHeight: { // 画布高度
|
||
Type: 'int',
|
||
default: 500
|
||
},
|
||
shareTitle: { // 分享标题
|
||
Type: 'String',
|
||
default: '我是这张图片的标题'
|
||
},
|
||
goodsTitle: { // 商品宣传标题
|
||
Type: 'String',
|
||
default: '我是这张图片的标题我是这张图片的标题我是这张图片的标'
|
||
},
|
||
shareImage: { // 分享图片
|
||
Type: 'String',
|
||
default: '/static/bg.jpg'
|
||
},
|
||
qrSize: { // 二维码大小
|
||
Type: 'int',
|
||
default: 100
|
||
},
|
||
qrUrl: { // 生成二维码的链接
|
||
Type: 'String',
|
||
default: 'https://ext.dcloud.net.cn/plugin?id=5747'
|
||
}
|
||
},
|
||
components: {
|
||
QRCode
|
||
},
|
||
data() {
|
||
return {
|
||
qrCode: '', // 二维码
|
||
}
|
||
},
|
||
mounted() {
|
||
_this = this;
|
||
},
|
||
methods: {
|
||
// 创建二维码
|
||
canvasCreate() {
|
||
_this.$refs.qrcode.make({
|
||
size: _this.qrSize,
|
||
text: _this.qrUrl
|
||
})
|
||
.then(res => {
|
||
// 返回的res与uni.canvasToTempFilePath返回一致
|
||
// console.log(res)
|
||
_this.qrCode = res.tempFilePath;
|
||
_this.onCanvas();
|
||
});
|
||
},
|
||
// 画图
|
||
async onCanvas() {
|
||
uni.showLoading({
|
||
title: "分享图片生成中..."
|
||
});
|
||
const ctx = uni.createCanvasContext(_this.canvasID, _this);
|
||
// 设置 canvas 背景色
|
||
ctx.setFillStyle('#FFFFFF');
|
||
ctx.fillRect(0, 0, _this.canvasWidth, _this.canvasHeight);
|
||
ctx.setFillStyle('#000000');
|
||
// 背景图片
|
||
ctx.drawImage(_this.shareImage, 50, 50);
|
||
ctx.setFontSize(18);
|
||
ctx.setTextAlign('center');
|
||
ctx.fillText(_this.shareTitle, _this.canvasWidth / 2, 30);
|
||
// 左边标题
|
||
ctx.setTextAlign('left')
|
||
ctx.setFontSize(16)
|
||
_this.writeTextOnCanvas(ctx, 30, 21, _this.goodsTitle, 50, 350);
|
||
// 设置虚线
|
||
ctx.setStrokeStyle('#333333');
|
||
ctx.setLineDash([5, 10], 2);
|
||
ctx.beginPath();
|
||
ctx.moveTo(220, 340);
|
||
ctx.lineTo(220, 420);
|
||
ctx.stroke();
|
||
// 二维码
|
||
ctx.drawImage(_this.qrCode, 225, 330, 100, 100);
|
||
// ctx.draw();
|
||
|
||
// 延迟后渲染至canvas上
|
||
let pic = await _this.setTime(ctx)
|
||
_this.$emit('success', pic);
|
||
},
|
||
/**
|
||
* @param {Object} ctx_2d getContext("2d") 对象
|
||
* @param {int} lineheight 段落文本行高
|
||
* @param {int} bytelength 设置单字节文字一行内的数量
|
||
* @param {string} text 写入画面的段落文本
|
||
* @param {int} startleft 开始绘制文本的 x 坐标位置(相对于画布)
|
||
* @param {int} starttop 开始绘制文本的 y 坐标位置(相对于画布)
|
||
*/
|
||
writeTextOnCanvas(ctx_2d, lineheight, bytelength, text, startleft, starttop) {
|
||
// 获取字符串的真实长度(字节长度)
|
||
function getTrueLength(str) {
|
||
var len = str.length,
|
||
truelen = 0;
|
||
for (var x = 0; x < len; x++) {
|
||
if (str.charCodeAt(x) > 128) {
|
||
truelen += 2;
|
||
} else {
|
||
truelen += 1;
|
||
}
|
||
}
|
||
return truelen;
|
||
}
|
||
// 按字节长度截取字符串,返回substr截取位置
|
||
function cutString(str, leng) {
|
||
var len = str.length,
|
||
tlen = len,
|
||
nlen = 0;
|
||
for (var x = 0; x < len; x++) {
|
||
if (str.charCodeAt(x) > 128) {
|
||
if (nlen + 2 < leng) {
|
||
nlen += 2;
|
||
} else {
|
||
tlen = x;
|
||
break;
|
||
}
|
||
} else {
|
||
if (nlen + 1 < leng) {
|
||
nlen += 1;
|
||
} else {
|
||
tlen = x;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return tlen;
|
||
}
|
||
for (var i = 1; getTrueLength(text) > 0; i++) {
|
||
var tl = cutString(text, bytelength);
|
||
ctx_2d.fillText(text.substr(0, tl).replace(/^\s+|\s+$/, ""), startleft, (i - 1) * lineheight +
|
||
starttop);
|
||
text = text.substr(tl);
|
||
}
|
||
},
|
||
// 彻底改成同步 防止拿到的图片地址为空
|
||
setTime(ctx) {
|
||
return new Promise((resole, err) => {
|
||
setTimeout(() => {
|
||
ctx.draw(false, async () => {
|
||
let pic = await _this.getNewPic();
|
||
resole(pic)
|
||
});
|
||
}, 600)
|
||
})
|
||
},
|
||
// 获取新的图片地址
|
||
getNewPic() {
|
||
return new Promise((resolve, errs) => {
|
||
setTimeout(() => {
|
||
uni.canvasToTempFilePath({
|
||
canvasId: _this.canvasID,
|
||
quality: 1,
|
||
complete: (res) => {
|
||
// 在H5平台下,tempFilePath 为 base64
|
||
// 关闭showLoading
|
||
uni.hideLoading();
|
||
// 储存海报地址 也是分享的地址
|
||
resolve(res.tempFilePath)
|
||
}
|
||
}, _this);
|
||
}, 200)
|
||
})
|
||
},
|
||
},
|
||
mounted() {
|
||
_this = this;
|
||
}
|
||
}
|
||
</script> |