Sline
Sline
  • 发布:2025-09-16 17:28
  • 更新:2025-09-16 19:16
  • 阅读:28

求助下画布生成图片失败

分类:HBuilderX

最新的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>
2025-09-16 17:28 负责人:无 分享
已邀请:
陌上华年

陌上华年

你这用法不对吧?
https://doc.dcloud.net.cn/uni-app-x/component/canvas.html

<template>  
  <canvas id="canvas"></canvas>  
</template>  
<script setup>  
  onReady(() => {  
    // HBuilderX 4.25+  
    // 异步调用方式, 跨平台写法  
    uni.createCanvasContextAsync({  
      id: 'canvas',  
      component: getCurrentInstance().proxy,  
      success: (context : CanvasContext) => {  
        const canvasContext = context.getContext('2d')!;  
        const canvas = canvasContext.canvas;  

        // 处理高清屏逻辑  
        const dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;  
        canvas.width = canvas.offsetWidth * dpr;  
        canvas.height = canvas.offsetHeight * dpr;  
        canvasContext.scale(dpr, dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale  
      }  
    })  
  })  
</script>  

要回复问题请先登录注册