uni-app中drawImage绘制图片空白,尝试过onload还是空白,是图片还没加载完成吗?

uni-app中drawImage绘制图片渲染空白,没报错,查看元素也有宽高。

应该是图片没加载完成就drawImage了,但是按照搜索到的解决方法在img.onload中drawImage也没解决,在img.onload中绘制,刷新页面,有时候有图片,有时候空白。

最后好像只有setTimeout才能解决,但是setTimeout的延迟时间应该设置为多少也不好确定,我试过0不行,至少要20ms才能稳定正常显示。

我还试过在img.onload回调中await img.decode()等待图片解码,在这个模拟里似乎解决了,但是在项目里也是有时正常,有时空白。

有人知道为什么会这样吗,onload 和 decode() 按理说应该已经确保了加载和解码完成,为什么还会空白?除了设置setTimeout 延迟,还有别的解决方案吗?

运行环境: H5
uni-app版本: 4.76
浏览器版本: Chrome 140.0.7339.186(正式版本) (64 位)

<template>
  <view class="content">
    <view class="body">
        <canvas 
          :style="{
            width: `${adjustedImageWidth}px`,
            height:`${adjustedImageHeight}px`
          }" 
          :canvas-id="canvasId" 
          class="canvas-img">
        </canvas>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      adjustedImageHeight: 0,
      adjustedImageWidth: 0,
      canvasId: 'myCanvas'
    };
  },
  onLoad() {
    console.log('onLoad')
    this.updateImageScaleInfo();
  },
  methods: {
    updateImageScaleInfo(imageIndex) {
      const imagePath = 'https://images.pexels.com/photos/19990334/pexels-photo-19990334.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load';
      uni.downloadFile({
        url: imagePath,
        success: (downloadRes) => {
          const tempFilePath = downloadRes.tempFilePath;
          uni.getImageInfo({
            src: tempFilePath,
            success: (res) => {
              const systemInfo = uni.getSystemInfoSync();
              const { safeArea } = systemInfo;
              const imageHeight = res.height
              const imageWidth = res.width
              const containerWidth = systemInfo.windowWidth - safeArea.left;
              const containerHeight = (imageHeight / imageWidth) * containerWidth;
              this.adjustedImageHeight = containerWidth;
              this.adjustedImageWidth = containerHeight;
              // setTimeout(() => {
              //   this.startNewCanvasContext(tempFilePath);
              // }, 500);
              let img = new Image()
              img.src = tempFilePath
              img.onload = () => {
                this.startNewCanvasContext(tempFilePath)
              }
              // this.startNewCanvasContext(tempFilePath)
            }
          });
        }
      });
    },
    startNewCanvasContext(imagePath) {
      this.context = uni.createCanvasContext(this.canvasId, this);
      this.context.drawImage(imagePath, 0, 0, this.adjustedImageWidth, this.adjustedImageHeight);
      console.log('绘制图片', imagePath);
      this.context.draw();
    }
  }
};
</script>
阅读 1.1k
2 个回答

将 onLoad 换成 mounted

  mounted() {
      setTimeout(()=>{
        this.$nextTick(()=>{
            this.updateImageScaleInfo();
        })
      }, 1000)
    },

使用 uni.getImageInfo 获取本地路径 + uni.createCanvasContext 绘制 + draw(false, callback) 确认绘制完成

uni.getImageInfo({
  src: imagePath,
  success: (res) => {
    const ctx = uni.createCanvasContext(this.canvasId, this);
    ctx.drawImage(res.path, 0, 0, this.adjustedImageWidth, this.adjustedImageHeight);
    ctx.draw(false, () => {
      console.log('绘制完成');
    });
  },
  fail: (err) => {
    console.error('获取图片信息失败', err);
  }
});

完整代码

<template>
  <view class="content">
    <view class="body">
      <canvas 
        :style="{
          width: `${adjustedImageWidth}px`,
          height: `${adjustedImageHeight}px`
        }" 
        :canvas-id="canvasId" 
        class="canvas-img">
      </canvas>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      adjustedImageHeight: 0,
      adjustedImageWidth: 0,
      canvasId: 'myCanvas'
    };
  },
  onLoad() {
    console.log('页面加载');
    this.updateImageScaleInfo();
  },
  methods: {
    updateImageScaleInfo() {
      const imagePath = 'https://images.pexels.com/photos/19990334/pexels-photo-19990334.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load';

      // 下载图片,确保是本地路径
      uni.downloadFile({
        url: imagePath,
        success: (downloadRes) => {
          const tempFilePath = downloadRes.tempFilePath;

          // 获取图片信息(宽高)
          uni.getImageInfo({
            src: tempFilePath,
            success: (res) => {
              const systemInfo = uni.getSystemInfoSync();
              const { safeArea } = systemInfo;

              const imageWidth = res.width;
              const imageHeight = res.height;
              const containerWidth = systemInfo.windowWidth - safeArea.left;
              const containerHeight = (imageHeight / imageWidth) * containerWidth;

              this.adjustedImageWidth = containerWidth;
              this.adjustedImageHeight = containerHeight;

              // 开始绘制图片
              this.startNewCanvasContext(res.path); // 使用 res.path 是关键
            },
            fail: (err) => {
              console.error('获取图片信息失败', err);
            }
          });
        },
        fail: (err) => {
          console.error('下载图片失败', err);
        }
      });
    },

    startNewCanvasContext(imagePath) {
      const ctx = uni.createCanvasContext(this.canvasId, this);

      ctx.drawImage(imagePath, 0, 0, this.adjustedImageWidth, this.adjustedImageHeight);

      // 使用 draw(false, callback) 确认绘制完成
      ctx.draw(false, () => {
        console.log('图片绘制完成');
      });
    }
  }
};
</script>

<style>
.canvas-img {
  border: 1px solid #ccc;
}
</style>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题