feat:更新core 和首页代码
This commit is contained in:
@@ -3,11 +3,57 @@
|
||||
* 封装微信小程序 Canvas API,为未来 Web 平台迁移做准备
|
||||
*/
|
||||
|
||||
type QueryHost =
|
||||
| WechatMiniprogram.Page.TrivialInstance
|
||||
| WechatMiniprogram.Component.TrivialInstance;
|
||||
|
||||
type Canvas2DContextLike = WechatMiniprogram.RenderingContext & {
|
||||
scale: (x: number, y: number) => void;
|
||||
};
|
||||
|
||||
export interface CanvasInitResult {
|
||||
canvas: WechatMiniprogram.Canvas;
|
||||
ctx: CanvasRenderingContext2D;
|
||||
ctx: Canvas2DContextLike;
|
||||
width: number;
|
||||
height: number;
|
||||
dpr: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与架构文档 ICanvasAdapter 对齐的小程序实现
|
||||
*/
|
||||
export interface ICanvasAdapter {
|
||||
getCanvas(): WechatMiniprogram.Canvas;
|
||||
getContext(): Canvas2DContextLike;
|
||||
getSize(): { width: number; height: number; dpr: number };
|
||||
setSize(width: number, height: number): void;
|
||||
loadImage(src: string): Promise<WechatMiniprogram.Image>;
|
||||
toDataURL(type?: 'png' | 'jpg', quality?: number): Promise<string>;
|
||||
toBlob(): Promise<unknown>;
|
||||
toTempFilePath(options?: {
|
||||
quality?: number;
|
||||
fileType?: 'png' | 'jpg';
|
||||
}): Promise<string>;
|
||||
}
|
||||
|
||||
function createQuery(host?: QueryHost): WechatMiniprogram.SelectorQuery {
|
||||
if (host && typeof host.createSelectorQuery === 'function') {
|
||||
return host.createSelectorQuery();
|
||||
}
|
||||
return wx.createSelectorQuery();
|
||||
}
|
||||
|
||||
function getDpr(): number {
|
||||
try {
|
||||
return Math.max(1, wx.getSystemInfoSync().pixelRatio || 1);
|
||||
} catch {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function ensureAspectRatio(aspectRatio: number): number {
|
||||
if (!Number.isFinite(aspectRatio) || aspectRatio <= 0) return 1;
|
||||
return aspectRatio;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15,43 +61,53 @@ export interface CanvasInitResult {
|
||||
* @param selector Canvas 选择器 (如 '#canvasContent')
|
||||
* @param wrapperSelector 容器选择器 (如 '#canvasWrapper')
|
||||
* @param aspectRatio 宽高比 (width / height)
|
||||
* @param host 可选:页面/组件实例,组件内调用建议传入 this
|
||||
*/
|
||||
export function initCanvas(
|
||||
selector: string,
|
||||
wrapperSelector: string,
|
||||
aspectRatio: number,
|
||||
host?: QueryHost,
|
||||
): Promise<CanvasInitResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const query = wx.createSelectorQuery();
|
||||
query
|
||||
const ratio = ensureAspectRatio(aspectRatio);
|
||||
createQuery(host)
|
||||
.select(wrapperSelector)
|
||||
.boundingClientRect((rect) => {
|
||||
if (!rect) {
|
||||
if (!rect || !rect.width) {
|
||||
reject(new Error('Canvas wrapper not found'));
|
||||
return;
|
||||
}
|
||||
|
||||
const boxWidth = rect.width;
|
||||
const boxHeight = boxWidth / aspectRatio;
|
||||
const boxHeight = boxWidth / ratio;
|
||||
|
||||
wx.createSelectorQuery()
|
||||
createQuery(host)
|
||||
.select(selector)
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res) => {
|
||||
if (!res[0]) {
|
||||
if (!res || !res[0] || !res[0].node) {
|
||||
reject(new Error('Canvas node not found'));
|
||||
return;
|
||||
}
|
||||
|
||||
const canvas = res[0].node;
|
||||
const ctx = canvas.getContext('2d');
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
const canvas = res[0].node as WechatMiniprogram.Canvas;
|
||||
const ctx = canvas.getContext(
|
||||
'2d',
|
||||
) as Canvas2DContextLike;
|
||||
const dpr = getDpr();
|
||||
|
||||
canvas.width = boxWidth * dpr;
|
||||
canvas.height = boxHeight * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
resolve({ canvas, ctx, width: boxWidth, height: boxHeight });
|
||||
resolve({
|
||||
canvas,
|
||||
ctx,
|
||||
width: boxWidth,
|
||||
height: boxHeight,
|
||||
dpr,
|
||||
});
|
||||
});
|
||||
})
|
||||
.exec();
|
||||
@@ -69,9 +125,9 @@ export function canvasToTempFilePath(
|
||||
wx.canvasToTempFilePath({
|
||||
canvas,
|
||||
fileType: options?.fileType || 'png',
|
||||
quality: options?.quality || 1,
|
||||
quality: options?.quality ?? 1,
|
||||
success: (res) => resolve(res.tempFilePath),
|
||||
fail: reject,
|
||||
fail: (err) => reject(err),
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -86,7 +142,64 @@ export function loadImage(
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = canvas.createImage();
|
||||
img.onload = () => resolve(img);
|
||||
img.onerror = reject;
|
||||
img.onerror = (err) => reject(err);
|
||||
img.src = src;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过初始化结果创建微信 Canvas 适配器实例
|
||||
*/
|
||||
export function createWxCanvasAdapter(init: CanvasInitResult): ICanvasAdapter {
|
||||
let width = init.width;
|
||||
let height = init.height;
|
||||
let dpr = init.dpr;
|
||||
let scaled = true;
|
||||
|
||||
const applyScale = () => {
|
||||
if (!scaled) {
|
||||
init.ctx.scale(dpr, dpr);
|
||||
scaled = true;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getCanvas() {
|
||||
return init.canvas;
|
||||
},
|
||||
getContext() {
|
||||
return init.ctx;
|
||||
},
|
||||
getSize() {
|
||||
return { width, height, dpr };
|
||||
},
|
||||
setSize(nextWidth: number, nextHeight: number) {
|
||||
width = Math.max(1, nextWidth);
|
||||
height = Math.max(1, nextHeight);
|
||||
dpr = getDpr();
|
||||
init.canvas.width = width * dpr;
|
||||
init.canvas.height = height * dpr;
|
||||
scaled = false;
|
||||
applyScale();
|
||||
},
|
||||
loadImage(src: string) {
|
||||
return loadImage(init.canvas, src);
|
||||
},
|
||||
async toDataURL(type = 'png', quality = 1) {
|
||||
const maybeCanvas = init.canvas as unknown as {
|
||||
toDataURL?: (mimeType?: string, q?: number) => string;
|
||||
};
|
||||
if (typeof maybeCanvas.toDataURL === 'function') {
|
||||
const mimeType = type === 'jpg' ? 'image/jpeg' : 'image/png';
|
||||
return maybeCanvas.toDataURL(mimeType, quality);
|
||||
}
|
||||
throw new Error('toDataURL is not supported in current runtime');
|
||||
},
|
||||
async toBlob() {
|
||||
throw new Error('toBlob is not supported in WeChat Mini Program');
|
||||
},
|
||||
toTempFilePath(options) {
|
||||
return canvasToTempFilePath(init.canvas, options);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user