uni-app写微信小程序分享海报

    技术2023-11-04  100

    需求:有用户头像,用户昵称,活动标题,商品主图,商品标题,商品价格,小程序二维码

    思路:写成一个js文件,就可以在需要的组件中混入使用(mixins),调用绘制函数:createCanvasImage('posterCanvas'),保存图片函数:saveCanvasImage。

    方法:canvas的dom元素的top写很大,相当于隐藏。canvas画好后,调用getCanvasImage函数得到图片(posterImg)显示。

    调用的组件dom代码:<canvas class="canvas" canvas-id="posterCanvas"></canvas>  <image :src="posterImg" class="img" />

    注释:<!-- canvas 要放在调用的组件里(外面),不能放在封装组件里面 会找不到 canvas-->

    js代码:

    export default {   data() {     return {       posterObj: {         url: "", //商品主图         userImg: "", //用户头像         nickname: "", //用户昵称         dec: "", //介绍         title: "", //标题         discountPrice: "", //折后价格         orignPrice: "", //原价         code: "", //小程序码       },       canvasFlag: true, // 是否显示canvas       posterImg: "",//canvas绘制后得到的图片       x: 25, // 绘制起点x       y: 0, // 绘制起点y       w: 270, // 绘制宽度       h: 345, // 绘制高度       radius: 10, // 圆角       padding: 10, // 边距       imgW: 187.5, // 主图片宽       imgH: 187.5, //主图片高       imgBg: "#f7f7f7", //主图片背景色     };   },   methods: {     // 画圆角矩形 ctx、x起点、y起点、w宽度、h高度、r圆角半径、fillColor填充颜色、strokeColor边框颜色     roundRect(ctx, x, y, w, h, r, fillColor, strokeColor, btn) {       // 开始绘制       ctx.beginPath();       // 绘制左上角圆弧 Math.PI = 180度       // 圆心x起点、圆心y起点、半径、以3点钟方向顺时针旋转后确认的起始弧度、以3点钟方向顺时针旋转后确认的终止弧度       ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);       // 绘制border-top       // 移动起点位置 x终点、y终点       ctx.moveTo(x + r, y);       // 画一条线 x终点、y终点       ctx.lineTo(x + w - r, y);       // 绘制右上角圆弧       ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);       // 绘制border-right       ctx.lineTo(x + w, y + h - r);       // 绘制右下角圆弧       ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);       // 绘制左下角圆弧       ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);       // 绘制border-left       ctx.lineTo(x, y + r);       if (btn == "btn") {         const grd = ctx.createLinearGradient(0, 0, 200, 0); //渐变色         grd.addColorStop(0, fillColor);         grd.addColorStop(1, strokeColor);         // 因为边缘描边存在锯齿,最好指定使用 transparent 填充         ctx.setFillStyle(grd);         // 对绘画区域填充         ctx.fill();       } else {         if (fillColor) {           // 因为边缘描边存在锯齿,最好指定使用 transparent 填充           ctx.setFillStyle(fillColor);           // 对绘画区域填充           ctx.fill();         }         if (strokeColor) {           // 因为边缘描边存在锯齿,最好指定使用 transparent 填充           ctx.setStrokeStyle(strokeColor);           // 画出当前路径的边框           ctx.stroke();         }       }       // 关闭一个路径       ctx.closePath();       // 剪切,剪切之后的绘画绘制剪切区域内进行,需要save与restore 这个很重要 不然没办法保存       ctx.clip();       // console.log("画圆角");     },     /**      * canvas绘图相关,把文字转化成只能行数,多余显示省略号      * ctx: 当前的canvas      * text: 文本      * contentWidth: 文本最大宽度      * lineNumber: 显示几行      */     canvasMultiLineText(ctx, text, contentWidth, lineNumber) {       var textArray = text.split(""); // 分割成字符串数组       var temp = "";       var row = [];       for (let i = 0; i < textArray.length; i++) {         if (ctx.measureText(temp).width < contentWidth) {           temp += textArray[i];         } else {           i--; // 这里添加i--是为了防止字符丢失           row.push(temp);           temp = "";         }       }       row.push(temp);       // 如果数组长度大于2,则截取前两个       if (row.length > lineNumber) {         var rowCut = row.slice(0, lineNumber);         var rowPart = rowCut[1];         var test = "";         var empty = [];         for (var a = 0; a < rowPart.length; a++) {           if (ctx.measureText(test).width < contentWidth) {             test += rowPart[a];           } else {             break;           }         }         empty.push(test); // 处理后面加省略号         var group = empty[0] + "...";         rowCut.splice(lineNumber - 1, 1, group);         row = rowCut;       }       return row;     },     // 绘制图片 : 当前canvas 图 x起点 y起点 w宽度 h高度 r圆角 c1填充颜色 c2边框颜色     drawImg(ctx, img, x, y, w, h, r, c1, c2) {       let _this = this;       //将网络图片转成本地路径       ctx.restore();       uni.getImageInfo({         src: img,         success(res) {           ctx.save();           //覆盖绘制           //问题:在微信小程序使用canvas绘制圆角图片时,微信调试工具正常显示,android真机都不显示。           // 原因:因为ctx.clip()剪切区域使用的填充颜色是透明的,所以图片没出来。           // 解决方案:将剪切区域设置成实体颜色就好了。           _this.roundRect(ctx, x, y, w, h, r, c1, c2); //绘制图片圆角背景           ctx.drawImage(res.path, x, y, w, h, r); //绘制图           ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 可以继续绘制           ctx.draw(true);         },         fail() {           _this.canvasFlag = true;           uni.showToast({ title: "img生成失败", duration: 2000, icon: "none" });         },       });     },     // 绘制文本 : 当前canvas 文本 x起点 y起点 c填充颜色 s样式     drawText(ctx, text, x, y, c, s) {       ctx.setFillStyle(c);       ctx.font = s;       ctx.fillText(text, x, y);       ctx.draw(true);     },     // 绘制两行标题 : 当前canvas 文本 x起点 y起点 c填充颜色 s样式     drawTitle(ctx, text, x, y, c, s) {       ctx.setGlobalAlpha(1); //不透明       ctx.setFillStyle(c); //文字颜色:默认黑色       ctx.font = s;       let row = this.canvasMultiLineText(ctx, text, 180, 2); //计算绘制的2行文本       let leftSpace = x + 10; // 这段文字起始的X位置       let textLineHeight = 18; // 一行文字加一行行间距       for (let b = 0; b < row.length; b++) {         //一行一行绘制文本         ctx.fillText(row[b], leftSpace, y + textLineHeight * b - 15, 180);         ctx.draw(true);       }     },     // 绘制价格 : 当前canvas 现价 原价 x起点 y起点     drawPrice(ctx, zpPrice, orignPrice, x, y) {       ctx.setFillStyle("#FF354D"); //文字颜色:默认黑色       ctx.setFontSize(21); //设置字体大小,默认10       let zpPriceW = ctx.measureText(zpPrice).width; //文本的宽度       ctx.fillText(`${zpPrice}`, x, y + 30, zpPriceW);       ctx.beginPath(); //开始一个新的路径       ctx.setFontSize(14); //设置字体大小,默认10       ctx.setFillStyle("#999"); //文字颜色:默认黑色       let orignPriceW = ctx.measureText(orignPrice).width; //去掉市场价       ctx.fillText(`¥${orignPrice}`, x + zpPriceW, y + 30, orignPriceW); //5价格间距       ctx.moveTo(x + zpPriceW, y + 25); //设置线条的起始路径坐标       ctx.lineTo(x + zpPriceW + orignPriceW, y + 25); //设置线条的终点路径坐标       ctx.setStrokeStyle("#999");       ctx.stroke(); //对当前路径进行描边       ctx.closePath(); //关闭当前路径     },     // 生成海报     createCanvasImage(id) {       // console.log(this.posterObj, "posterObj");       uni.showLoading({         title: "海报生成中...",       });       let _this = this;       const ctx = uni.createCanvasContext(id);       ctx.draw(); //清空原来的画图内容       ctx.save();       this.roundRect(ctx, this.x, this.y, this.w, this.h, this.radius, "#fff", "#fff"); //绘制海报圆角背景白色的       ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图上下午即状态 可以继续绘制       ctx.save();       //将网络图片转成本地路径 用户头像       this.drawImg(         ctx,         this.posterObj.userImg,         this.x + this.padding,         this.y + this.padding,         50,         50,         25,         this.imgBg,         this.imgBg       );       // 用户昵称       this.drawText(ctx, this.posterObj.nickname, this.x + 70, this.y + 30, "#333", "normal bold 18px sans-serif");       // dec介绍       this.drawText(ctx, this.posterObj.dec, this.x + 70, this.y + 55, "#666", "normal 14px sans-serif");       //将网络图片转成本地路径 商品图片       this.drawImg(         ctx,         this.posterObj.url,         this.x + 41,         this.y + 70,         this.imgW,         this.imgH,         this.radius,         this.imgBg,         this.imgBg       );       // 海报商品title       let contentTextY = this.y + 295; // 这段文字起始的y位置       _this.drawTitle(ctx, this.posterObj.title, this.x, contentTextY, "#333", "normal bold 14px sans-serif");       //绘制价格       this.drawPrice(ctx, this.posterObj.discountPrice, this.posterObj.orignPrice, this.x + this.padding, contentTextY);       // 二维码 图标       this.drawImg(ctx, this.posterObj.code, this.x + 200, this.y + 271, 60, 60, 0, "#ffffff", this.imgBg);       setTimeout(() => {         this.getCanvasImage(id);         setTimeout(() => {           uni.hideLoading();         }, 300);       }, 300);     },     getCanvasImage(id) {       let _this = this;       // 把画布转化成临时文件       uni.canvasToTempFilePath({         x: _this.x,         y: _this.y,         quality: 1,         width: this.w,         height: this.h,         destWidth: this.w * 10,         destHeight: this.h * 10,         canvasId: id,         success(res) {           _this.posterImg = res.tempFilePath;         },         fail() {           uni.showToast({ title: "生成失败,稍后再试", duration: 2000, icon: "none" });         },       });     },     // 保存到系统相册     saveCanvasImage() {       uni.showLoading({         title: "保存中...",       });       let _this = this;       // 保存图片至相册       uni.saveImageToPhotosAlbum({         filePath: _this.posterImg,         success(res2) {           uni.hideLoading();           uni.showToast({ title: "图片保存成功,可以去分享啦~", icon: "none", duration: 2000 });           _this.canvasCancelEvn();         },         fail() {           uni.showToast({ title: "保存失败,稍后再试", duration: 2000, icon: "none" });           uni.hideLoading();         },       });     },     // 取消海报     canvasCancelEvn() {       // console.log();       this.$emit("cancel", true);     },   }, };

     

    Processed: 0.009, SQL: 10