最新的HBuilderX 阿尔法,uniappx,在网页预览器预览的时候,点击生成的时候,没法把画布生成图片地址,图片地址一直是空的。放了个日志发现实例又是空的。AI怎么改都改不对,请哪位大神帮忙看下,我已经删除无关代码了,可以直接运行查看。
<template>
<view class="container"
style="padding: 20rpx; background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d); color: #333; box-sizing: border-box;">
<view class="content" style="display: flex; flex-direction: column; gap: 30rpx;">
<view class="control-panel"
style="background: rgba(255, 255, 255, 0.92); padding: 0rpx; border-radius: 12rpx; box-shadow: 0 8rpx 25rpx rgba(0, 0, 0, 0.15); ">
<!-- 高级模式设置 -->
<button class="btn generate-btn" @tap="generateAndPreview"
style="position: fixed; bottom: 40rpx; height: 120rpx; left: 50%; transform: translateX(-50%); width: 80%!important; max-width: 700rpx!important; z-index: 100; box-shadow: 0 8rpx 25rpx rgba(0, 0, 0, 0.3); background: linear-gradient(135deg, #3498db, #1abc9c); display: flex; flex-direction: column; justify-content: center; border-radius: 100rpx;">
<view class="btn-text" style="font-size: 1.4rem; font-weight: bold; color: white;">开始生成</view>
</button>
</view>
</view>
<!-- 隐藏的普通画布 -->
<canvas canvas-id="mazeCanvas" id="mazeCanvas" type="2d"
:style="{width: state.canvasWidth + 'px', height: state.canvasHeight + 'px'}"></canvas>
</view>
</template>
<script setup>
import { reactive, onMounted, onUnmounted } from 'vue';
import { getCurrentInstance } from 'vue';
const instance = getCurrentInstance();
// 响应式数据
const state = reactive({
canvas: null,
canvasContext: null,
mazeTitle: '迷宫大冒险',
canvasWidth: 300,
canvasHeight: 300,
isGenerating: false,
generationCancelled: false,
generationProgress: 0,
currentPage: 1,
totalPages: 1,
currentCanvasSize: 'A4',
customWidth: 794,
customHeight: 1123,
CANVAS_SIZES: {
A4: { width: 794, height: 1123 },
A3: { width: 1123, height: 1587 }
},
MAX_CANVAS_WIDTH: 2000,
MAX_CANVAS_HEIGHT: 2000
});
onMounted(() => {
// 初始化画布
initCanvas();
});
onUnmounted(() => {
if (state.canvas) {
state.canvas = null;
state.canvasContext = null;
}
cancelGenerate();
});
// 初始化画布
const initCanvas = () => {
const query = uni.createSelectorQuery();
query.select('#mazeCanvas')
.fields({ node: true, size: true })
.exec((res) => {
if (res && res[0]) {
const canvas = res[0].node;
const ctx = canvas.getContext('2d');
// 设置画布实际尺寸
canvas.width = state.canvasWidth;
canvas.height = state.canvasHeight;
ctx.fillStyle = '#226161';
ctx.fillRect(0, 0, canvas.width, canvas.height);
state.canvas = canvas;
state.canvasContext = ctx;
}
});
};
const calculatePages = () => {
state.totalPages = 1;
state.currentPage = 1;
};
const renderToCanvas = async (resolve, reject) => {
console.log('[Render] 开始渲染画布');
const { canvasWidth, canvasHeight } = state;
if (canvasWidth <= 0 || canvasHeight <= 0) {
console.error('[Render] 无效的画布尺寸', { canvasWidth, canvasHeight });
reject(new Error(`无效的画布尺寸: ${canvasWidth}x${canvasHeight}`));
return;
}
try {
console.log('[Render] 初始化/重用画布');
let canvas = state.canvas;
let ctx = state.canvasContext;
if (!canvas || !ctx) {
console.error('[Render] 画布未初始化');
reject(new Error('画布未初始化'));
return;
}
console.log('[Render] 清空画布');
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
console.log('[Render] 绘制背景');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
console.log('[Render] 绘制标题');
ctx.fillStyle = '#2c3e50';
ctx.font = '28px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(state.mazeTitle || '迷宫生成工具', 200, 40);
console.log('[Render] 准备导出图片');
await new Promise((resolveDraw) => setTimeout(resolveDraw, 200));
const currentInstance = getCurrentInstance();
if (!currentInstance) {
throw new Error('无法获取组件实例');
}
uni.canvasToTempFilePath({
canvasId: 'mazeCanvas',
success: (res) => {
console.log('[Render] 图片导出成功', res);
resolve(res.tempFilePath);
},
fail: (err) => {
console.error('[Render] 图片导出失败', err);
reject(new Error(`图片导出失败: ${err.errMsg}`));
}
}, currentInstance.proxy);
} catch (err) {
console.error('[Render] 渲染过程中发生错误', err);
reject(new Error(`创建画布失败: ${err.message}`));
}
};
const generateAndPreview = () => {
if (state.isGenerating) {
uni.showToast({
title: '正在生成中...',
icon: 'none'
});
return;
}
state.isGenerating = true;
state.generationCancelled = false;
state.generationProgress = 0;
uni.showLoading({
title: '绘制中 (0%)',
mask: true
});
calculatePages();
const totalPages = Math.min(state.totalPages, 10);
const pageImages = [];
const pageQueue = Array.from({ length: totalPages }, (_, i) => i + 1);
const startTime = Date.now();
const generateNextPage = () => {
if (state.generationCancelled) {
uni.hideLoading();
return;
}
if (pageQueue.length === 0) {
const duration = (Date.now() - startTime) / 1000;
console.log(`生成完成,耗时: ${duration}s`);
uni.hideLoading();
if (pageImages.length > 0) {
uni.navigateTo({
url: `/pages/index/preview?pageImages=${encodeURIComponent(JSON.stringify(pageImages))}&totalPages=${pageImages.length}`,
});
} else {
uni.showToast({
title: '生成图片失败',
icon: 'none'
});
}
state.isGenerating = false;
return;
}
const page = pageQueue.shift();
try {
state.currentPage = page;
const progress = Math.round(((pageImages.length) / totalPages) * 100);
uni.showLoading({
title: `生成图片 (${progress}%)`,
mask: true
});
state.generationProgress = progress;
new Promise((resolve, reject) => {
renderToCanvas(resolve, reject);
}).then(imagePath => {
pageImages.push(imagePath);
setTimeout(generateNextPage, 100);
}).catch(err => {
console.error(`第${page}页生成失败`, err);
setTimeout(generateNextPage, 100);
});
} catch (err) {
console.error(`生成第${page}页异常`, err);
setTimeout(generateNextPage, 100);
}
};
generateNextPage();
};
const cancelGenerate = () => {
if (state.isGenerating) {
state.generationCancelled = true;
state.isGenerating = false;
uni.hideLoading();
uni.showToast({
title: '已取消生成',
icon: 'none'
});
}
};
</script>
1 个回复
陌上华年
你这用法不对吧?
https://doc.dcloud.net.cn/uni-app-x/component/canvas.html