uniapp 编译支付宝小程序canvas 合成图片实例,支付宝小程序 canvas 渲染图片 可以换成自己的图片即可

文章目录

  • 前言
  • [一、在页面中使用 Canvas](#一、在页面中使用 Canvas)
  • [二、在页面的 JS 文件中绘制图片](#二、在页面的 JS 文件中绘制图片)
  • 总结

前言

uniapp 编译支付宝小程序canvas 合成图片实例,支付宝小程序 canvas 渲染图片 可以换成自己的图片即可


一、在页面中使用 Canvas

html 复制代码
<template>
  <view>
    <!-- Canvas 画布 -->
    <canvas 
      type="2d" 
	  :id="alipayCanvasId"
      :style="canvasStyle"
      :width="canvasWidth" :height="canvasHeight"
      @ready="onCanvasReady" 
    />
    
    <!-- 生成的海报预览 -->
    <image 
      v-if="finalPosterUrl" 
      :src="finalPosterUrl" 
      mode="widthFix" 
      style="width: 100%; margin-top: 20rpx"
      show-menu-by-longpress="true"
    />
  </view>
</template>

二、在页面的 JS 文件中绘制图片

你可以使用 myCanvas 这个 canvas-id 来获取 canvas 上下文,并绘制图片。

javascript 复制代码
<script>
export default {
  data() {
    return {
      finalPosterUrl: '', // 生成的海报临时路径
	  alipayCanvasId:"alipayPosterCanvas",
      alipayCanvas: null,  // Canvas 实例
      alipayCtx: null,     // 2D 上下文
      dpr: 1,        // 设备像素比
      // Canvas 基础配置
      canvasWidth: 0, // 动态计算的canvas宽度
      canvasHeight: 0, // 动态计算的canvas高度
      canvasStyle: "", // canvas样式
    };
  },
  
  methods: {
    /**
     * Canvas 就绪回调
     */
    onCanvasReady() {
      // 图片资源
      const mainImgUrl = 'xxxxxx/haibao_image.png';
      const qrImgUrl = 'xxxxxx/0379ec3faccad8485f136bd94b1486e1e367ac8c.jpeg';

      // 查询 Canvas 节点
      uni.createSelectorQuery()
 // 绑定当前组件上下文(关键)
        .select(`#${this.alipayCanvasId}`)
        .node()
        .exec(async (res) => {
          if (!res || !res[0] || !res[0].node) {
            console.error('未找到 Canvas 节点');
            return;
          }

          // 初始化 Canvas 环境
          this.initCanvasEnv(res[0].node);

          try {
            // 分步加载并绘制图片(使用封装的方法)
            const mainImg = await this.loadImage(mainImgUrl);
            this.drawMainImage(mainImg);
            
            const qrImg = await this.loadImage(qrImgUrl);
            this.drawQrCode(qrImg);

            // 转换为临时图片
            this.convertToTempImage();
          } catch (err) {
            console.error('海报生成失败:', err);
            uni.showToast({ title: '生成失败', icon: 'none' });
          }
        });
    },

    /**
     * 初始化 Canvas 环境(尺寸、上下文等)
     */
    initCanvasEnv(canvasNode) {
      this.alipayCanvas = canvasNode;
      this.alipayCtx = canvasNode.getContext('2d');
      
      // 获取设备信息
      const sysInfo = uni.getSystemInfoSync();
      this.dpr = sysInfo.pixelRatio || 1;
      
      // 计算逻辑宽高(750rpx = 屏幕宽度)
      this.canvasWidth = sysInfo.screenWidth;
      this.canvasHeight = (1200 / 750) * sysInfo.screenWidth;
      
      // 设置实际像素尺寸(解决模糊问题)
      this.alipayCanvas.width = this.canvasWidth * this.dpr;
      this.alipayCanvas.height = this.canvasHeight * this.dpr;
      
      // 缩放上下文
      this.alipayCtx.scale(this.dpr, this.dpr);
    },

    /**
     * 封装:加载图片(支持网络图片下载 + Canvas 图片对象转换)
     * @param {String} url - 图片URL
     * @returns {Promise} - 加载完成的图片对象
     */
    loadImage(url) {
      return new Promise(async (resolve, reject) => {
        try {
          // 1. 下载网络图片(支付宝需要先下载为本地临时路径)
          const tempPath = await this.downloadImage(url);
          
          // 2. 将临时路径转换为 Canvas 可绘制的图片对象
          const img = this.alipayCanvas.createImage();
          img.onload = () => resolve(img);
          img.onerror = () => reject(new Error(`图片加载失败: ${url}`));
          img.src = tempPath; // 使用下载后的临时路径
        } catch (err) {
          reject(err);
        }
      });
    },

    /**
     * 封装:下载网络图片为本地临时路径
     * @param {String} url - 图片URL
     * @returns {Promise} - 本地临时路径
     */
    downloadImage(url) {
      return new Promise((resolve, reject) => {
        // 校验URL有效性
        if (!url || typeof url !== 'string') {
          reject(new Error(`无效的图片URL: ${url}`));
          return;
        }

        uni.downloadFile({
          url,
          success: (res) => {
            if (res.statusCode === 200) {
              resolve(res.tempFilePath); // 返回临时路径
            } else {
              reject(new Error(`下载失败,状态码: ${res.statusCode}`));
            }
          },
          fail: (err) => {
            reject(new Error(`下载错误: ${err.errMsg}`));
          }
        });
      });
    },

    /**
     * 绘制主图
     * @param {Object} img - 主图图片对象
     */
    drawMainImage(img) {
      // 铺满整个画布
      this.alipayCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight);
    },

    /**
     * 绘制二维码
     * @param {Object} img - 二维码图片对象
     */
    drawQrCode(img) {
      // 二维码尺寸(画布宽度的30%)
      const qrSize = this.canvasWidth * 0.3;
      // 二维码位置(底部居中,距离底部20rpx)
      const qrX = (this.canvasWidth - qrSize) / 2;
      const qrY = this.canvasHeight - qrSize - (20 / 750) * this.canvasWidth;

      // 绘制白色背景(增强对比度)
      this.alipayCtx.fillStyle = '#ffffff';
      this.alipayCtx.fillRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
      
      // 绘制二维码
      this.alipayCtx.drawImage(img, qrX, qrY, qrSize, qrSize);
    },

    /**
     * 转换 Canvas 为临时图片
     */
    convertToTempImage() {
      uni.canvasToTempFilePath({
        canvasId: this.alipayCanvasId,
        width: this.canvasWidth,
        height: this.canvasHeight,
        destWidth: this.canvasWidth * this.dpr, // 输出高清图
        destHeight: this.canvasHeight * this.dpr,
        success: (res) => {
          this.finalPosterUrl = res.tempFilePath;
          console.log('海报生成成功:', res.tempFilePath);
        },
        fail: (err) => {
          console.error('转换图片失败:', err);
          uni.showToast({ title: '转换失败', icon: 'none' });
        }
      }, this);
    }
  }
};
</script>

总结

注意事项

‌跨域问题‌:如果图片 URL 是外部链接,确保服务器支持跨域请求,或者在支付宝小程序管理后台添加图片的域名到"业务域名"白名单中。

‌图片加载‌:由于网络请求和图片加载可能需要时间,建议在 onReady 或在图片加载成功后调用 drawImage 方法。

‌动态图片‌:如果图片是动态生成的或者来自用户上传,确保在调用 drawImage 前图片已经加载完成。可以使用 my.getImageInfo 方法获取图片信息,例如尺寸等,然后再进行绘制。

相关推荐
小时前端19 小时前
微信小程序选不了本地文件?用 web-view + H5 一招搞定
前端·微信小程序·uni-app
Mr_li2 天前
给 Vue 开发者的 uni-app 快速指南
vue.js·uni-app
anyup2 天前
🔥2026最推荐的跨平台方案:H5/小程序/App/鸿蒙,一套代码搞定
前端·uni-app·harmonyos
Mintopia3 天前
Vue3 项目如何迁移到 uni-app x:从纯 Web 到多端应用的系统指南
uni-app
Mintopia3 天前
uni-app x 发展前景技术分析:跨端统一的新阶段?
uni-app
不爱说话郭德纲3 天前
告别漫长的HbuilderX云打包排队!uni-app x 安卓本地打包保姆级教程(附白屏、包体积过大排坑指南)
android·前端·uni-app
HashTang5 天前
【AI 编程实战】第 12 篇:从 0 到 1 的回顾 - 项目总结与 AI 协作心得
前端·uni-app·ai编程
JunjunZ5 天前
uniapp 文件预览:从文件流到多格式预览的完整实现
前端·uni-app
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
TT_Close6 天前
“啪啪啪”三下键盘,极速拉起你的 uni-app 项目!
vue.js·uni-app·前端工程化