给客户倒腾了个新功能 呃 也不算新功能了吧 之前很早也给客户做过 就是初始需求不太一样 今天这个客户的需求是 每天上架的新商品 需要生成一个长图海报 客户可以分享到朋友圈 或者发到群里 给自己的用户们看到 因为每天上线出售的商品不一样 如果没有这样一个长图海报 就需要每天自己辛苦截图 或者其他办法来告知用户 今天有些什么产品在卖这样 莫名增加了很多无用的劳动 而且明显的有点傻...😃
研究了下 小程序这边还是准备用Canvas 新开一个画布 先请求获取一下客户今天上线的商品 然后把商品的图片 标题 价格 作为数据源 让Canvas进行绘制 一行2个商品 一行一行的往下绘制 绘制完之后 在头部增加 今日出售商品 底部增加小程序的码 长图海报生成之后 用户可以长按识别进入小程序直接购买 客户每天就拿长图发个朋友圈 或者在群里发下长图海报就ok 一个 海报生成 按钮 就把之前的无用操作给省略了 不过测试了下 如果商品多的时候 绘制的过程耗时会稍微有点长 而且看下来 好像和跑小程序的手机有一定影响 手机强一些的话 绘制过程会短一点
需求说完啦 贴一下代码 界面这边 做了个image标签 装载绘制好了的长图海报
<view class="container-box"> <canvas canvas-id="posterCanvas" id="posterCanvas" /></view><view class="preview-area v-shadow b-radius-20" wx:if="{{postUrl}}"> <image src="{{postUrl}}" mode="widthFix" class="preview-image" /></view><view class="btn-v f-r-center w-bg-c"> <z-btn width="400" height='80' bind:tap='postImgSave' bg-color='#404040'> <text class="font-10">保存海报</text> </z-btn></view>
js文件有点多
async generatePoster() { const products = this.data.goodsOnSaleArr; // 1. 计算画布尺寸 const screenWidth = wx.getSystemInfoSync().screenWidth; const canvasWidth = screenWidth; // 2倍图清晰 const padding = 20 * 2; // 内边距 const columnCount = 2; // 两列 const columnGap = 10 * 2; const rowGap = 15 * 2; // 商品卡片尺寸 const cardWidth = (canvasWidth - padding * 2 - columnGap) / columnCount; const imageHeight = cardWidth * 1.2; // 图片高度 const titleHeight = 30; // 标题区域高度 const priceHeight = 30; // 价格区域高度 const cardHeight = imageHeight + titleHeight + priceHeight; // 计算行数和总高度 const rowCount = Math.ceil(products.length / columnCount); const canvasHeight = rowCount * (cardHeight + rowGap) + padding * 2; this.setData({ canvasWidth, canvasHeight }); // 2. 加载所有图片 const imagePromises = products.map(product => this.loadImage(product.t) ); const images = await Promise.all(imagePromises); // 3. 创建canvas上下文 const ctx = wx.createCanvasContext('posterCanvas'); // 4. 绘制背景 ctx.setFillStyle('#ffffff'); ctx.fillRect(0, 0, canvasWidth, canvasHeight); // 5. 绘制商品列表 for (let i = 0; i < products.length; i++) { const product = products[i]; const image = images[i]; // 计算位置 const row = Math.floor(i / columnCount); const col = i % columnCount; const x = padding + col * (cardWidth + columnGap); const y = padding + row * (cardHeight + rowGap); // 绘制商品卡片背景 ctx.setFillStyle('#f8f8f8'); ctx.fillRect(x, y, cardWidth, cardHeight); // 绘制商品图片 if (image) { //ctx.drawImage(image, x, y, cardWidth, imageHeight); this.drawRoundImage(ctx, image, x, y, cardWidth, imageHeight, 8); } // 绘制商品标题(增加顶部间距) ctx.setFontSize(16); ctx.setFillStyle('#1e1e1e'); ctx.setTextAlign('left'); const title = this.ellipsis(product.title, 10); const titleLines = this.getTextLines(ctx, title, cardWidth - 10); // 标题顶部间距 10px(2倍图为20) const titleTopMargin = 12 * 2; // 新增:标题顶部间距 titleLines.forEach((line, index) => { ctx.fillText( line, x + 10, y + imageHeight + titleTopMargin + index * 24 // 修改这里 ); }); // 绘制价格 ctx.setFontSize(18); ctx.setFillStyle('#e93b3b'); ctx.fillText( `¥${product.price}`, x + 10, y + cardHeight - 10 ); } // 6. 绘制完成 ctx.draw(false, () => { // 导出为图片 wx.canvasToTempFilePath({ canvasId: 'posterCanvas', success: (res) => { const url = res.tempFilePath; console.log('保存到相册或预览', res) this.setData({ postUrl: url }) }, fail: (err) => { console.error('生成海报失败:', err); } }); }); }, // 多行文本处理 getTextLines(ctx, text, maxWidth) { const lines = []; let currentLine = ''; const words = text.split(''); for (let i = 0; i < words.length; i++) { const testLine = currentLine + words[i]; const metrics = ctx.measureText(testLine); if (metrics.width > maxWidth && i > 0) { lines.push(currentLine); currentLine = words[i]; } else { currentLine = testLine; } } if (currentLine) { lines.push(currentLine); } // 限制最多显示2行 if (lines.length > 2) { lines.length = 2; lines[1] = lines[1].substring(0, lines[1].length - 1) + '...'; } return lines; }, // 保存海报到相册 postImgSave(e) { var that = this, urlVal = that.data.postUrl; wx.saveImageToPhotosAlbum({ filePath: urlVal, success: () => { wx.showToast({ title: '保存成功' }); } }); },
差不多就是上面这些 css文件的话 自己按照实际情况调整一下 有个问题没解决好 绘制的清晰度 导出的长图海报清晰度总是不太满意
这几天新版本的开发工具 没下载那个稳定版的 总觉得有点不稳定的小问题 不知道是不是我的问题 后期调整好了再来补充一下 这一期先这样
保持好奇 不断进步 下期见~