小程序二维码功能

This commit is contained in:
2026-07-12 23:59:52 +08:00
parent 1bd152073a
commit f2cdc0222d
10 changed files with 658 additions and 63 deletions
@@ -0,0 +1,75 @@
import { useEffect, useState } from 'react';
import { View, Canvas } from '@tarojs/components';
import Taro from '@tarojs/taro';
import {
REDEEM_QR_DISPLAY_SIZE,
buildRedeemQrDataUrl,
drawRedeemQrOnCanvas,
} from '../lib/redeem-qr';
const CANVAS_ID = 'redeem-qr-canvas';
type RedeemQrCodeProps = {
token: string;
};
function drawOnWeappCanvas(token: string) {
const page = Taro.getCurrentInstance().page;
const query = page ? Taro.createSelectorQuery().in(page) : Taro.createSelectorQuery();
query
.select(`#${CANVAS_ID}`)
.fields({ node: true, size: true })
.exec((res) => {
const item = res[0] as { node?: WechatMiniprogram.Canvas; width?: number; height?: number } | undefined;
const canvas = item?.node;
if (!canvas) return;
const layoutW = item.width || REDEEM_QR_DISPLAY_SIZE;
const layoutH = item.height || REDEEM_QR_DISPLAY_SIZE;
const drawSize = Math.min(layoutW, layoutH);
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const dpr = Taro.getSystemInfoSync().pixelRatio || 2;
canvas.width = layoutW * dpr;
canvas.height = layoutH * dpr;
ctx.scale(dpr, dpr);
drawRedeemQrOnCanvas(ctx, token, drawSize);
});
}
export default function RedeemQrCode({ token }: RedeemQrCodeProps) {
const [imgSrc, setImgSrc] = useState('');
const isWeapp = process.env.TARO_ENV === 'weapp';
useEffect(() => {
if (!token) {
setImgSrc('');
return;
}
if (isWeapp) {
const timer = setTimeout(() => drawOnWeappCanvas(token), 120);
return () => clearTimeout(timer);
}
let cancelled = false;
void buildRedeemQrDataUrl(token).then((url) => {
if (!cancelled) setImgSrc(url);
});
return () => {
cancelled = true;
};
}, [token, isWeapp]);
return (
<View className="redeem-qr-box">
<View className="redeem-qr-placeholder" />
{isWeapp ? (
<Canvas type="2d" id={CANVAS_ID} canvasId={CANVAS_ID} className="redeem-qr-canvas" />
) : imgSrc ? (
<View className="redeem-qr-img" style={{ backgroundImage: `url(${imgSrc})` }} />
) : null}
<View className="redeem-qr-scanline" />
</View>
);
}