uni-app 小程序 canvas绘制文字无法及时响应最新数据并回显

发布于 1周前 作者 phonegap100 来自 Uni-App

uni-app 小程序 canvas绘制文字无法及时响应最新数据并回显

产品分类:

uniapp/小程序/微信

PC开发环境操作系统:

Windows

PC开发环境操作系统版本号:

Windows 10 专业版

HBuilderX类型:

正式

HBuilderX版本号:

4.29

第三方开发者工具版本号:

1.06.2409140 win32-x64

基础库版本号:

3.4.7

项目创建方式:

HBuilderX

示例代码:

// 开始绘制二维码   圆角
async created() {
    this.SystemInfo = await this.getSystemInfo();
    this.ewmImg = await this.getImageInfo(this.invitationCode);
    this.bgImg = await this.getImageInfo(this.bgImgUrl);
    this.xcxImg = await this.getImageInfo(this.xcxCode);
    if (this.SystemInfo.errMsg == 'getSystemInfo:ok' && this.ewmImg.errMsg == 'getImageInfo:ok' && this
        .bgImg.errMsg == 'getImageInfo:ok' && this.xcxImg.errMsg == 'getImageInfo:ok') {
        // 
        uni.showLoading({
            title: '绘制中...'
        });
        // canvas名称、背景图片、小程序二维码、头像、编号(目前没啥用)可以用来判断给那个变量赋值
        await this.canvasDrawFn('inviteQrcode', this.bgImg.path, this.xcxImg.path, this.ewmImg.path, 1);
    } else {
        console.log('err')
    }
},
// 绘制方法 这样可以减少更多相同的写法
canvasDrawFn(eventName, bgImg, xcxImg, ewmImg, code) {
    try {
        let that = this;
        let bgX = 287; // 背景宽度
        let bgY = 392; // 背景高度
        // 防止他不是获取不到 canvas-id
        var ctx = uni.createCanvasContext(eventName, this);
        ctx.drawImage(bgImg, 0, 0, bgX, bgY);
        const avatarSize = 46; // 头像的尺寸(假设是正方形)
        const radius = avatarSize / 2; // 半径
        // 背景图片的距离 / 2
        const centerX = bgX / 2; // 圆形裁剪位置 X
        const centerY = bgY / 2; // 圆形裁剪位置 Y
        
        let newCenterX = (centerX - 2);
        let newCenterY = (centerY - 64);
        
        // 收入
        ctx.setFillStyle('#fe3c39');
        ctx.font = `bold 24px PingFangSC-Regular`;
        const pleaseTextUiInfo = ctx.measureText(`收入${this.amount}元`);
        console.log('多少', this.amount);
        ctx.fillText(`收入${this.amount}元`, (bgX - pleaseTextUiInfo.width) / 2, (bgY - 180));
        // 成功上榜
        ctx.setFillStyle('#fe3c39');
        ctx.font = `bold 16px PingFangSC-Regular`;
        const pleaseTextUiInfo1 = ctx.measureText(`我成功上榜!`);
        ctx.fillText(`我成功上榜!`, ((bgX - pleaseTextUiInfo1.width) / 2) + 7, (bgY - 150));
        // 城市地区
        ctx.setFillStyle('#75280f');
        ctx.font = `16px PingFangSC-Regular`;
        const pleaseTextUiInfo2 = ctx.measureText(`排名${this.regionName}城市第${this.ranking}名`);
        ctx.fillText(`排名${this.regionName}城市第${this.ranking}名`, ((bgX - pleaseTextUiInfo2.width) / 2), (bgY -
        125));
        // 二维码
        ctx.drawImage(xcxImg, (bgX - 110), (bgY - 110), 75, 75);
        // 设置圆角头像
        ctx.beginPath();
        ctx.arc(newCenterX, newCenterY, radius, 0, 2 * Math.PI, false);
        ctx.clip();
        // 计算绘制位置,使头像居中
        const avatarX = newCenterX - radius; // 头像左上角 X 坐标
        const avatarY = newCenterY - radius; // 头像左上角 Y 坐标
        ctx.drawImage(ewmImg, avatarX, avatarY, avatarSize, avatarSize);
        setTimeout(() => {
            ctx.draw(true, (ret) => {
                uni.hideLoading();
                uni.canvasToTempFilePath({
                    canvasId: eventName,
                    fileType: 'jpg',
                    success(res) {
                        // 里面用that 不要用this,要不然使用里面的东西不生效
                        console.log('绘制成功', res);
                        if (code == 1) {
                            that.tempPath = res.tempFilePath;
                        } else if (code == 2) {
                            that.newTempPath = res.tempFilePath;
                        }
                    },
                    complete(error) {
                        // 这也是成功
                        if (error.errMsg == 'canvasToTempFilePath:ok') {
                            if (code == 1) {
                                that.tempPath = error.tempFilePath;
                            } else if (code == 2) {
                                that.newTempPath = error.tempFilePath;
                            }
                        } else {
                            console.error('绘制图片报错:', error);
                        }
                    }
                }, this); // 在子组件中 canvasToTempFilePath 要加一个this 仅限 小程序需要
            });
        }, 200);
    } catch (e) {
        //TODO handle the exception
    }
},

操作步骤:

进入排行榜页面 默认是日榜,点击分享数据正常,然后在切换周榜或月榜,在点击分享,数据还是日榜的数据,打印是最新的数据

预期结果:

每次切换榜单的时候获取最新的数据进行展示分享,并下载

实际结果:

只有第一次点开后是正确的,往后文字都没有根据我传递的数据进行变更,只有头像变更了

bug描述:

在uniapp小程序中,使用canvas绘制文字的时候疑似缓存问题(又不太像)因为我只有文字被缓存了,头像是最新的,我在子组件进行绘制的时候父组件把所需的数据都传递到子组件中,子组件通过props接受都是最新的数据,第一次打开数据是正确的,但是关闭后切换数据,在打开canvas组件数据一直显示是第一次的数据 image image


2 回复

代码在APP中是正常的,只有在小程序会出现canvas文字没有改变的问题,然后头部切换都是在父组件完成的,只有点击分享会把通过组件的ref去掉子组件的方法,让他自己打开,并绘制数据展示


在uni-app中,使用canvas绘制文字时,如果遇到无法及时响应最新数据并回显的问题,通常是因为canvas的绘制操作是异步的,且绘制过程需要在特定的生命周期函数或事件回调中进行。为了确保canvas能够及时响应并绘制最新的数据,你可以通过以下方式优化代码:

  1. 使用canvas.draw(false, callback)确保绘制完成:在绘制完成后,通过回调函数确保最新的数据已经被绘制。

  2. 在数据更新时重新绘制:确保在数据变化时,能够触发canvas的重新绘制。

下面是一个简单的代码示例,展示如何在uni-app中使用canvas绘制文字,并确保其能够及时响应数据变化:

<template>
  <view>
    <canvas canvas-id="myCanvas" style="width: 300px; height: 200px;"></canvas>
    <button @click="updateText">Update Text</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      text: 'Hello, uni-app!'
    };
  },
  methods: {
    drawCanvas() {
      const ctx = uni.createCanvasContext('myCanvas');
      ctx.setFontSize(20);
      ctx.setFillStyle('black');
      ctx.fillText(this.text, 50, 100);
      ctx.draw(false, () => {
        console.log('Canvas drawing completed');
      });
    },
    updateText() {
      this.text = 'New Text Updated!';
      this.$nextTick(() => {
        this.drawCanvas();
      });
    }
  },
  mounted() {
    this.drawCanvas();
  }
};
</script>

<style scoped>
/* 添加必要的样式 */
</style>

解释

  1. 模板部分:包含一个canvas元素和一个按钮,点击按钮会触发updateText方法。

  2. 脚本部分

    • data中定义了一个text变量,用于存储要绘制的文字。
    • drawCanvas方法使用uni.createCanvasContext获取canvas上下文,并设置字体大小、颜色,然后绘制文字。绘制完成后,通过回调函数输出绘制完成的消息。
    • updateText方法更新text变量的值,并在$nextTick中调用drawCanvas方法重新绘制canvas,确保数据更新后canvas能立即响应。
    • mounted生命周期钩子中调用drawCanvas进行初始绘制。

通过这种方式,可以确保canvas能够及时响应并显示最新的数据。

回到顶部