2***@qq.com
2***@qq.com
  • 发布:2026-04-14 09:26
  • 更新:2026-04-14 09:29
  • 阅读:179

在ios系统上,剪切版与画布有冲突

分类:uni-app

uni.showLoading({
title: '海报生成中,请耐心有等待...',
mask: true,
});
let imgurl = await createCanvas(item);
//await createCanvas(item);
uni.hideLoading();

    copyText(item.content)  
    // #ifdef MP-WEIXIN  
    uni.showShareImageMenu({  
        path: imgurl,  
        needShowEntrance: false,  
    });  
    // #endif  

    uni.getClipboardData({  
        success: (res) => {  
            console.log('剪贴板内容:', res.data);  
        },  
        fail: (err) => {  
            console.error('获取剪贴板内容失败:', err);  
        }  
    })  

其中 // 复制文本
const copyText = (text) => {
const cleanText = convertToTextWithBreaks(text);
uni.setClipboardData({
data: cleanText,
success: (res) => {
console.log('复制成功:', res);
uni.showToast({
title: '复制成功',
icon: 'success',
});
},
fail: () => {
uni.showToast({
title: '复制失败',
icon: 'none',
});
},
});
};

现在控制台报
09:19:15.787 复制成功:, [Object] {"errMsg":"setClipboardData:ok"} at pages/jiaolian.vue:274
09:19:15.787 获取剪贴板内容失败:, [Object] {"errMsg":"getClipboardData:fail"} at pages/jiaolian.vue:631

这个问题只是在ios上出现,安卓正常,小程序和鸿蒙没有测试。

如果我不执行createCanvas这个方法,那剪切板的内容正常获取得到,只要一执行createCanvas方法, 不管copyText方法和绘制之前还是在绘制之后,都再也获取不到内容。

以下是careteCanvas方法的代码

const createCanvas = async (item) => {  
    if (!item.coverImage) return ''  
    // 1. 确保头像和二维码已加载  
    try {  
        if (!avatarPath.value || !qrcodePath.value) {  
            await initAvatarQrcode();  
        }  
        let imagePathUrl = null  
        let imgInfo = null  
        let imgWidth = null  
        let imgHeight = null  
        if (item.coverImage) {  
            imagePathUrl = await downloadFile(item.coverImage)  
            imgInfo = await getImageInfo(imagePathUrl);  
            imgWidth = screenWidth.value;  
            let ratioVal = screenWidth.value / imgInfo.width  
            screenHeight.value = imgInfo.height * ratioVal  
            imgHeight = screenHeight.value  
            await new Promise((resolve, reject) => {  
                nextTick(() => {  
                    setTimeout(() => {  
                        resolve()  
                    }, 50)  
                })  
            })  
        }  
        const ctx = uni.createCanvasContext('posterCanvas', this);  
        // 清空并设置背景  
        ctx.clearRect(0, 0, imgWidth, imgHeight);  
        // ctx.fillStyle = '#FFFFFF';  
        ctx.fillRect(0, 0, imgWidth, imgHeight);  

        // 绘制图片  
        ctx.drawImage(imagePathUrl, 0, 0, imgWidth, imgHeight);  
        // 二. 绘制用户信息区域(放在图片下方)  
        let bgXPos = 0  
        let bgYPos = imgHeight - (imgHeight / 5)  

        // 绘制圆形头像  
        const avatarY = bgYPos + 40  
        ctx.save()  
        ctx.beginPath()  
        ctx.arc(55, avatarY, 35, 0, 2 * Math.PI)  
        ctx.closePath()  
        ctx.clip()  
        ctx.drawImage(avatarPath.value, 20, avatarY - 35, 70, 70)  
        ctx.restore()  
        // 2.绘制二维码  
        let qrXPos = imgWidth - 130  
        let qrYPos = bgYPos  
        ctx.drawImage(qrcodePath.value, qrXPos + 30, qrYPos, 80, 80);  
        // 4.绘制用户信息  
        // 4.1绘制驾校名称  
        ctx.setFillStyle('#515151');  
        let textX = bgXPos + 100;  
        ctx.font = 'bold 18px sans-serif';  

        let text = jiaolian.value.nickname  
        if (text.length > 8) {  
            text = text.substring(0, 8) + '...'  
        }  
        ctx.fillText(text, textX, bgYPos + 30);  
        // 5.1绘制招生电话  
        ctx.font = 'nobold 14px sans-serif';  
        ctx.fillText(jiaolian.value.mobile, textX, bgYPos + 60);  
        // 执行绘制 - 使用回调确保绘制完成  
        ctx.draw();  

        return new Promise((resolve, reject) => {  
            setTimeout(() => {  
                uni.canvasToTempFilePath({  
                    canvasId: 'posterCanvas',  
                    width: imgWidth,  
                    height: imgHeight,  
                    destWidth: imgWidth * 3,  
                    destHeight: imgHeight * 3,  
                    success: (res) => {  
                        resolve(res.tempFilePath);  
                    },  
                    fail: (err) => {  
                        console.error('canvasToTempFilePath失败:', err);  
                        reject(err);  
                    }  
                }, this); // 注意这里的this指向  
            }, 100); // 稍微延迟确保绘制完成  
        });  
    } catch (err) {  
        console.error('海报生成异常:', err);  
        uni.showToast({  
            title: '海报生成失败',  
            icon: 'none',  
        });  
        throw err;  
    }  
};  
2026-04-14 09:26 负责人:无 分享
已邀请:
Ask小助手

Ask小助手 - Ask社区AI助手

欢迎到专业群( uni-app 官方技术交流群 1 ) 咨询,群中有相关专业的管理员和群友。

根据知识库中的信息,iOS 系统对剪贴板的访问有严格的权限和时机限制,特别是在涉及异步操作(如画布生成)后,uni.getClipboardData 可能会出现获取失败的情况。

建议改用 Native.js 方式操作剪贴板,可以避免 iOS 平台的限制。插件市场提供了封装好的解决方案:

使用 操作系统粘贴板 插件(dc-clipboard),该插件基于 Native.js 实现,可设置/获取系统粘贴板中的文本内容,且不会弹出默认的 toast 提示。

使用方法:

  1. 下载插件保存到项目目录,如 common/dc-clipboard/clipboard.js
  2. 在页面中引用:
    import clipboard from "@/common/dc-clipboard/clipboard.js"  

    本助手使用国产模型,生成代码可能不准确。专业的代码生成需要全球顶尖的AI Coding模型。推荐使用uni-agent

  3. 调用方法:

    // 设置剪贴板  
    clipboard.setText('需要复制的文本');  
    
    // 获取剪贴板  
    var text = clipboard.getText();  
    console.log(text);  

    本助手使用国产模型,生成代码可能不准确。专业的代码生成需要全球顶尖的AI Coding模型。推荐使用uni-agent

注意事项:

  • 该插件仅 App 端可用(iOS/Android)
  • 相比 uni.setClipboardDatauni.getClipboardData,使用 Native.js 方式可以避免 iOS 系统对剪贴板访问的异步限制
  • 如需要在设置剪贴板后隐藏默认提示,也可在使用 uni.setClipboardData 后立即调用 uni.hideToast()

另外,建议调整代码执行顺序,确保剪贴板操作尽可能在用户交互(如点击事件)的同步上下文中执行,避免在异步操作(如画布生成)之后再进行剪贴板读取操作。

内容为 AI 生成,仅供参考

要回复问题请先登录注册