JavaScript异步加载图片

本文介绍了如何在JavaScript中使用异步加载图片,特别是在画板应用中遇到的问题和解决方案。当使用橡皮擦功能时,由于canvas只能显示一张图片,有时会导致擦除后只剩原始图片。为解决这个问题,作者提出了在擦除后异步加载原始图片和擦除后的图片,通过合并这两张图片来形成完整的擦除效果。文章还展示了如何封装异步加载图片的函数,确保图片加载完成后再执行后续操作,从而避免加载问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址: https://www.jeremyjone.com/526/ ,转载请注明


之前写的画板里面,我将它升级了一下,首先可以传入一张默认图片,然后所有操作都是基于该图片进行操作。然后我发现,当使用橡皮擦的时候,它直接将整个canvas擦成了透明。

这是因为canvas每次只能展示一张图片,这个在之前说过,有兴趣的朋友可以参考之前的文章。

于是有了很简单的想法,在擦除完成后,首先在canvas中加载原始图片,然后加载擦除后的图片,这样重叠合并成一张完整的擦除后的效果图。

有了想法,动手做:

// 首先保存擦除的图片
let eraserPic = new Image();
eraserPic.src = this.canvasElem.toDataURL("image/png");

// 加载原始图片
let originPic = new Image();
originPic.src = this.originImage;

// 对原始图片响应,这里需要使用`load`响应,否则会有神奇的效果。。。
originPic.addEventListener("load", () => {
    this.ctx.drawImage(originPic, 0, 0, this.canvasElem.width, this.canvasElem.height);

    // 先加载原始图,然后加载擦除后的图片,这样原始图片在下,擦除图片在上面,进行合并
    eraserPic.addEventListener("load", () => {
        this.ctx.drawImage(eraserPic, 0, 0, this.canvasElem.width, this.canvasElem.height);

        // 保存合并后的图片
        this.capturePic = this.canvasElem.toDataURL("image/png");

        // 将新图片添加到undo区域,方便后续操作
        this.undoPushHandle();
    });
});

然后发现真实可用,但是发现总会有问题,时不常一擦除就清空,只显示原始图。多次检查后,感觉是load事件的加载问题,图片加载是一个等待过程,但是我们的代码操作的很快,这样就会出现没有监听到,代码认为不需要load,也就不会加载load里面的事件。

一开始我把所有addEventListener都写在了一层,发现问题后,套了进去,还是有小概率机会出现不加载的问题,于是想到了Promise

使用异步加载图片

异步的内容很简单,封装一个新建Image的函数,让所有图片都加载好之后返回即可。这样就可以完全等待图片加载成功后执行下一步。

newImageProcess: function(src) {
    return new Promise((resolve, reject) => {
        let img = new Image();
        // 因为有些地方获取图片需要使用跨域截图,所有添加到这里
        img.setAttribute("crossOrigin", "anonymous");
        img.onload = () => resolve(img);
        img.onerror = reject;
        // src赋值在最后,这样做更加保险可以调用`load`事件。
        img.src = src;
    })
}

有了这段代码,后面的操作就行云流水般的简单明了了。

this.newImageProcess(this.canvasElem.toDataURL("image/png")).then((result) => {
    // 首先加载擦除后的图片,保存为变量
    let eraserPic = result;

    this.newImageProcess(this.originImage).then((result) => {
        // 然后加载原始图片,同样保存为变量
        let originPic = result;

        // 依次在canvas中加载原始图片和擦除后图片,使其合并为一张最终效果图
        this.ctx.drawImage(originPic, 0, 0, this.canvasElem.width, this.canvasElem.height);
        this.ctx.drawImage(eraserPic, 0, 0, this.canvasElem.width, this.canvasElem.height);

        // 保存图片并添加到undo操作区域
        this.videoCapture = this.canvasElem.toDataURL("image/png");
        this.undoPushHandle();
    }).catch((err) => {
        console.log("origin error");
    });
}).catch((err) => {
    console.log("eraser error");
});

就这样,不仅代码简单很多,而且整洁干净,思路也清晰了很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值