- canvas封装成组件,绘制图片不显示?
<canvas id="image-cropping" canvas-id="image-cropping" :style="{ width: '408px', height: '510px' }"></canvas> 封装一个按想要比例截取图片的组件(imageCropping),页面上引用组件绘制图片时,显示不出来。id都是默认写死的。 [图片] 创建画布也是获取成功的,加了try内部也没有报错。也用过创建画布加this。 然后就是显示不出来。 下面是调试好的功能;自测可以使用。 参考代码: import { getCurrentInstance, ref } from 'vue'; import { useUploadFile } from '@/request/index'; import { getUuid, parseJson, showToast } from '@/utils/common'; import useRequestConfig from '@/request/config'; import type { UploadFileResponse } from './type'; const { REQUEST_SUCCESS_CODE } = useRequestConfig(); // 图片上传请求 const uploadRequest = useUploadFile(); // 获取当前实例: 否则绘制图片不显示 const instance = getCurrentInstance(); // canvas实例id const canvasId = `image-cropping-${getUuid()}`; interface PropsType { imageUrl: string; // 图片路径 aspectRatio: number; // 图片宽高比例 // 截取框的宽高和位置 width: number; height: number; } const props = withDefaults(defineProps<PropsType>(), { imageUrl: '', width: 0, height: 0, aspectRatio: 0.8, // 分享图片默认长宽比5:4 }); // 设置画布宽高 const canvasWidth = ref<number | string>(0); const canvasHeight = ref<number | string>(); // 获取画布,开始绘图 const createCanvasByImg = () => { return new Promise<void>(async (resolve) => { try { // 获取源图宽高信息 const imgInfo = await getOriginalImgInfo(); if (!imgInfo) return; // 获取图片截取宽高,和截取位置起始点(左上角) const { width, height, left, top } = getCanvasWH(imgInfo.width, imgInfo.height); // 画布宽高 = 截取图片宽高 canvasHeight.value = `${height}px`; canvasWidth.value = `${width}px`; // 创建画布实例 const ctx = uni.createCanvasContext(canvasId, instance); // 绘制图片: path-图片路径, (left,top)源图中截取的起始点对应(x,y)轴 // 第一组width/height,对应需要绘制的图片宽高,第二组width/height,对应图片截取的宽高 ctx.drawImage(imgInfo.path, left, top, width, height, 0, 0, width, height); // 画完之后,将图片转为图片 ctx.draw(false, async () => { // 等待生成图片地址 await getImageTemporaryUrl(); resolve(); }); // eslint-disable-next-line no-empty } catch (e) { resolve(); } }); }; /** * 根据宽高比例,设置画布高度 * @param imgH 图片高度 * @param imgW 图片宽度 */ const getCanvasWH = (imgW: number, imgH: number) => { // 初始剪切框宽高 const result = { width: props.width, height: props.height, left: 0, top: 0, }; // 根据具体图片长宽比和实际截取的长宽比,计算截取框的宽高 // 以图片最短的一边进行计算,尽量保证短的一边完整 if (imgH >= imgW) { // 初始化截取宽度 = 图片宽度 result.width = imgW; // 截取高度 = 图片宽度 * 高宽比 result.height = imgW * props.aspectRatio; // 如果截取高度比原图片高度大,需要按比例缩小截取宽度 if (result.height > imgH) { result.width = (result.height / imgH) * result.width; result.height = imgH; } } else { // 初始化截取高度 = 图片高度 result.height = imgH; // 截取宽度 = 图片高度 / 高宽比 result.width = imgH / props.aspectRatio; // 如果截取宽度比原图片宽度大,需要按比例缩小截取高度 if (result.width > imgW) { result.height = (result.width / imgW) * result.height; result.width = imgW; } } // 图片绘制开始位置偏移量 result.left = (imgW - result.width) / 2; result.top = (imgH - result.height) / 2; return result; }; // 将原图片转为临时图片,获取图片高/宽信息 const getOriginalImgInfo = () => { return new Promise<UniApp.GetImageInfoSuccessData | null>((resolve) => { uni.getImageInfo({ src: props.imageUrl, success: (res) => resolve(res), fail: () => resolve(null), }); }); }; // 将画布转为图片,获取临时图片地址(有时效,不能直接用于分享) let currentCanvasImagUrl = ''; const getImageTemporaryUrl = () => { return new Promise<string>((resolve) => { // 已有地址,不重复获取 if (currentCanvasImagUrl) return resolve(currentCanvasImagUrl); // 将画布转为图片获取临时地址 uni.canvasToTempFilePath( { canvasId: canvasId, success: (res) => { currentCanvasImagUrl = res.tempFilePath; resolve(res.tempFilePath); }, fail: () => resolve(''), }, instance ); }); }; // 图片上传到内部服务器 let currentUploadImgUrl = ''; const uploadImage = async () => { // 已上传过的图片,不重复上传 if (currentUploadImgUrl) return currentUploadImgUrl; // 获取图片临时地址 const imageTemporaryUrl = await getImageTemporaryUrl(); if (imageTemporaryUrl) { // 上传图片 const res = await uploadRequest.upload({ tag: '分享图片裁剪', timeout: 15000, filePath: imageTemporaryUrl, }); const uploadResult = parseJson<UploadFileResponse>(res as string); if (uploadResult && REQUEST_SUCCESS_CODE.includes(uploadResult.code)) { currentUploadImgUrl = uploadResult.data; } } // 图片上传失败,返回原图片地址 return currentUploadImgUrl || props.imageUrl; }; // 图片下载 const downloadImage = async () => { // 校验用户相册权限 const hasPermission = await checkSaveImagePermission(); if (!hasPermission) { // 自动调起获取相册权限 const result = await automaticSaveImagePermission(); // 如果没有授权成功,弹窗提示 if (!result) return showAuthTipModal(); } // 获取图片临时地址 const imageTemporaryUrl = await getImageTemporaryUrl(); if (!imageTemporaryUrl) return showToast('保存失败,请重试~'); // 下载图片 uni.saveImageToPhotosAlbum({ filePath: imageTemporaryUrl, success: () => showToast('保存成功'), fail: () => showToast('保存失败'), }); }; // 图片下载,相册权限校验 const checkSaveImagePermission = () => { return new Promise((resolve) => { uni.getSetting({ success: (res) => resolve(res.authSetting['scope.writePhotosAlbum']), fail: () => resolve(false), }); }); }; // 图片下载,相册权限校验未通过,自动呼起相册授权 const automaticSaveImagePermission = () => { return new Promise((resolve) => { uni.authorize({ scope: 'scope.writePhotosAlbum', success: () => resolve(true), fail: () => resolve(false), }); }); }; // 授权提示 const showAuthTipModal = () => { uni.showModal({ title: '授权提示', content: '是否允许获取保存相册权限', confirmColor: '#0a4cde', success: (res) => { if (res.confirm) { uni.openSetting({ success: (res) => { if (res.authSetting['scope.writePhotosAlbum']) { // 授权成功,再次下载图片 downloadImage(); } else { showToast('请确认相册权限已开启'); } }, }); } }, }); }; // 暴露接口 defineExpose({ createCanvasByImg, uploadImage, downloadImage, });
04-10 - 开发工具预览码和上传版本,报错不是开发者,实际有开发者权限?
开发工具预览码和上传版本,报错不是开发者,实际有开发者权限。 就刚刚2025年3月31日22点左右开始,开发工具突然显示不是开发者,前一秒我才发了预览码给测试, 测试扫码测试的时候反馈没有权限
03-31 - 开发工具没有鸿蒙机型?
目前开发工具中,没有鸿蒙机型选择。很多鸿蒙手机用户反馈很多小程序运行问题。
2024-12-30 - 小程序隐私协议同意后,授权页没有相关选项问题?
场景:小程序定位首选未开启,隐私授权未同意,到功能页面再同意隐私权限。 api: 使用openSetting,打开授权面板 操作步骤: 1、进入小程序,弹出隐私协议新页面,不同意,只浏览功能(进入小程序不同意隐私授权) 2、到功能页面,此时需要位置定位,重新打开了隐私页面,点击了同意(到功能页面,再同意隐私权限) 3、从隐私页面返回功能页面,此时获取定位,因位置未授权,切到微信授权页面,此时授权页面无位置授权选项 4、重进小程序-进入功能页-再切到微信授权页,此时位置授权选项又出现了
2024-04-19 - wx.setClipboardData,设置粘贴板,默认提示问题
小程序问题 问题背景: 设置粘贴板不带默认提示,之前是好的,小程序中设置了自定义提示,经过测试联调已上线。 今天看线上,默认提示突然恢复,导致用户点击复制,弹出多个提示内容
2024-04-18 - 使用js动态创建一个弹窗(vue组件)?
每个消息订阅入口添加提示蒙层。不想每个地方引入组件操作,想通过js调用动态为当前页面添加组件页面。 浏览器端可以使用document实现,小程序端如何实现??
2023-07-28 - 复制链接无法关闭?
看一下案例,以前小程序,分享按钮没有时,复制链接也会关闭。现在使用 hideShareMenu也无法关闭复制链接按钮。 而且页面可以分享,但是是自定义分享内容,也不希望开启复制链接。 期望能有单独的api控制按钮的显示
2023-07-14