已封装好的代码

<template><view class="canvas-content"><!-- 海报 --><canvas class="canvas" :style="'width: ' + canvasWith + 'px; height: ' + canvasHeight + 'px;'" canvas-id="myCanvas"></canvas><view class="button-wrapper"><!-- 保存海报按钮 --><button class="save-btn" @click="saveCanvasImage" v-if="isPhoto">保存海报</button><button class="save-btn" open-type="openSetting" @opensetting="getPhotoSetting" v-else>保存海报</button></view><view class="del-icon"><image @click="handleCanvasCancel" src="../../static/canvas/del.png" mode=""></image></view></view>
</template><script>
export default {data() {return {bgScale: 0.914, // 头部背景缩放比例 320 / canvasWith(350)aScale: 0.2, // 二维码缩放比例 120 / canvasWith(350)screenWidth: 750,canvasWith: 650,canvasHeight: 900,bgPic: {// 圆角背景宽高w: 320,h: 320},codePic: {// 二维码宽高w: 120,h: 120},codeImg: 'https://a.mushihulian.com/group1/M00/00/AE/rBGrr1-Pox-AJ6wLAAGlJGxOb4E997.png',isPhoto: true,canvasBgLink: '',canvasShow: false,system: null,attrs: {}};},props: {canvasAttr: {type: Object}},// 监听页面显示onShow() {        },mounted() {this.isSavePic();},methods: {// 保存图片的授权设置(二次授权情况下触发)getPhotoSetting(e) {const isTrue = e.detail.authSetting['scope.writePhotosAlbum'];this.isPhoto = isTrue ? true : false;},// 检测是否有授权保存图片功能,以显示不同按钮isSavePic() {uni.getSetting({success: res => {const isTrue = res.authSetting['scope.writePhotosAlbum'];if (isTrue === undefined) {this.isPhoto = true;} else {this.isPhoto = isTrue ? true : false;}}});},// 获取设备信息getSystem() {const system = uni.getSystemInfoSync();// console.log(system, '设备信息');const ratio = this.screenWidth / system.windowWidth;this.canvasHeight = this.canvasHeight / ratio;this.canvasWith = this.canvasWith / ratio;this.bgPic = {// 圆角白色背景宽高w: this.canvasWith * this.bgScale,h: this.canvasWith * this.bgScale};this.codePic = {// 二维码宽高w: this.canvasWith * this.aScale,h: this.canvasWith * this.aScale};},// 展示海报posterShow() {this.getSystem();// this.isSavePic();console.log(this.codeImg,this.canvasAttr, '咯');Object.assign(this.attrs, this.canvasAttr);this.creatPoster(this.attrs);},// 生成canvas海报creatPoster(canvasAttr) {const canvasWith = this.canvasWith;const canvasHeight = this.canvasHeight;const ctx = uni.createCanvasContext('myCanvas', this);// console.log(canvasAttr, '娃哈哈');ctx.draw(); //清空之前的海报ctx.save();// 圆角背景图ctx.restore();this.roundRect(ctx, 0,0, canvasWith, canvasHeight, 10, '#fff', canvasAttr.bgImg, true);ctx.save(); // 白色背景ctx.restore();// this.roundRect(ctx,this.canvasWith*0.044, canvasHeight-172, this.bgPic.h, 160, 10, '#fff');this.roundRect(ctx,12, canvasHeight-172, this.bgPic.h, 160, 10, '#fff');ctx.save();// 画圆形头像ctx.restore();this.drawCircular(ctx,canvasAttr,this.canvasWith*0.1,this.canvasHeight*0.55,40 ,40);ctx.save();// 文字ctx.setFillStyle('#000000'); // 文字颜色ctx.setFontSize(15); // 文字字号ctx.textAlign="start"; ctx.fillText('昵称一样', 76, canvasHeight-135); // 绘制文字ctx.setFillStyle('#666666'); // 文字颜色ctx.setFontSize(15); // 文字字号ctx.textAlign="start"; ctx.fillText('2020-09-16', 76, canvasHeight-116); // 绘制文字// ctx.beginPath();// // 设置线宽// ctx.lineWidth = 1;// 移动画笔至坐标 x20 y20 的位置ctx.moveTo(29, canvasHeight-100);// 绘制到坐标 x20 y100 的位置ctx.lineTo(this.bgPic.h-6, canvasHeight-100);// 填充颜色ctx.strokeStyle="#C4C4C4";// // 开始填充// ctx.stroke();// ctx.closePath();// ctx.save();// 画二维码ctx.restore();ctx.drawImage(canvasAttr.codeImg, this.canvasWith*0.69, canvasHeight-164, this.codePic.w, this.codePic.w);ctx.save();ctx.setFillStyle('#666666'); ctx.setFontSize(12); ctx.textAlign="start"; ctx.fillText('累计打卡', 32, canvasHeight-76);ctx.setFillStyle('#000000'); // ctx.setFontSize(26);ctx.textAlign="end"; ctx.fillText('210', this.bgPic.h-20, canvasHeight-70); ctx.setFillStyle('#666666'); // ctx.setFontSize(12);ctx.textAlign="end"; ctx.fillText('天', this.bgPic.h-6, canvasHeight-70); ctx.strokeStyle="#C4C4C4";//左ctx.moveTo(29, canvasHeight-60);// 绘制到坐标 x20 y100 的位置ctx.lineTo(this.bgPic.h-6, canvasHeight-60);ctx.stroke();ctx.setFillStyle('#666666');ctx.setFontSize(12); ctx.textAlign="start"; ctx.fillText('完成一亿部', 32, canvasHeight-40);ctx.setFillStyle('#666666');ctx.setFontSize(12); ctx.textAlign="start"; ctx.fillText('累计打卡', 32, canvasHeight-23);//经书名称ctx.setFillStyle('#000000');ctx.setFontSize(26);ctx.textAlign="end"; ctx.fillText('210', this.bgPic.h-20, canvasHeight-28); //经书数量ctx.setFillStyle('#666666'); ctx.setFontSize(12);ctx.textAlign="end"; ctx.fillText('部', this.bgPic.h-6, canvasHeight-28); //左右边距线// ctx.strokeStyle="red";//右// ctx.moveTo(this.bgPic.h-6,canvasHeight-180);// ctx.lineTo(this.bgPic.h-6,canvasHeight);// ctx.stroke();// ctx.strokeStyle="red";//右// ctx.moveTo(this.bgPic.h-20,canvasHeight-100);// ctx.lineTo(this.bgPic.h-20,canvasHeight);// ctx.stroke();// ctx.strokeStyle="red";//左// ctx.moveTo(29,canvasHeight-180);// ctx.lineTo(29,canvasHeight);// ctx.stroke();//绘制结束ctx.draw(true);},/*** 画圆形头像* @param { object } ctx : canvas上下文* @param { number } x : 圆心 x 轴坐标* @param { number } y : 圆心 y 轴坐标* @param { number } width : canvas上下文* @param { number } ctx:canvas上下文* 是否逆时针旋转: false 代表顺时针旋转* @author: wudidi*/drawCircular(ctx, canvasAttr, x, y, width, height) {ctx.save();let avatar_width = width,avatar_heigth = height,avatar_x = x,avatar_y = y;// 开始绘制路径ctx.beginPath();// 绘制圆的路径   0 即 0°是从三点钟方向开始的ctx.arc(avatar_width / 2 + avatar_x, avatar_heigth + avatar_y, avatar_width / 2, 0, Math.PI * 2, false);ctx.closePath();ctx.clip();ctx.setFillStyle('#F1F1F1');ctx.fill();ctx.drawImage(canvasAttr.handUrl, avatar_x, avatar_heigth / 2 + avatar_y, avatar_width, avatar_heigth);ctx.restore();},/*** 圆角背景* @param {CanvasContext} ctx canvas上下文* @param {number} x 圆角矩形选区的左上角 x坐标* @param {number} y 圆角矩形选区的左上角 y坐标* @param {number} w 圆角矩形选区的宽度* @param {number} h 圆角矩形选区的高度* @param {number} r 圆角的半径* @param {String} fillColor 填充颜色* @author: wudidi*/roundRect(ctx, x, y, w, h, r, fillColor = '#ffffff', url, isBg) {ctx.save();// 开始绘制ctx.beginPath();// 因为边缘描边存在锯齿,最好指定使用 transparent 填充ctx.setFillStyle('transparent');// 绘制左上角圆弧ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);// 绘制border-topctx.moveTo(x + r, y);ctx.lineTo(x + w - r, y);ctx.lineTo(x + w, y + r);// 绘制右上角圆弧ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);// 绘制border-rightctx.lineTo(x + w, y + h - r);ctx.lineTo(x + w - r, y + h);// 绘制右下角圆弧ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);// 绘制border-bottomctx.lineTo(x + r, y + h);ctx.lineTo(x, y + h - r);// 绘制左下角圆弧ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);// 绘制border-leftctx.lineTo(x, y + r);ctx.lineTo(x + r, y);ctx.fill();ctx.closePath();// 剪切ctx.clip();ctx.setFillStyle(fillColor);ctx.fillRect(x, y, w, h);if (isBg) {ctx.drawImage(url, 0,0, this.canvasWith, this.canvasHeight);}ctx.restore();},// 保存图片到相册async saveCanvasImage() {uni.showLoading({title: '海报保存中'});await this.createCanvasLink();console.log(this.canvasBgLink, '图片链接');if (this.canvasBgLink) {uni.getSetting({success: res => {if (res.authSetting['scope.writePhotosAlbum']) {this.savaPhotos();} else {uni.authorize({scope: 'scope.writePhotosAlbum',success: res => {this.savaPhotos();},fail: err => {this.isPhoto = false;}});}}}); } else {uni.hideLoading();uni.showToast({title: '海报保存失败',duration: 2000,icon: 'none'});}},// 把画布转化成临时文件createCanvasLink() {return new Promise((resolve, reject) => {uni.canvasToTempFilePath({x: 0,y: 0,width: this.canvasWith, // 画布的宽height: this.canvasHeight, // 画布的高canvasId: 'myCanvas',success: res => {this.canvasBgLink = res.tempFilePath;resolve({ res });},fail: () => {// uni.hideLoading();// uni.showToast({//     title: '海报生成失败 稍后再试',//     duration: 2000,//     icon: 'none'// });}},this);});},//保存图片至相册savaPhotos() {uni.saveImageToPhotosAlbum({filePath: this.canvasBgLink,success: res => {this.isPhoto = true;uni.hideLoading();this.handleCanvasCancel();},fail: err => {this.handleCanvasCancel();uni.hideLoading();uni.showToast({title: '海报保存失败',duration: 2000,icon: 'none'});}});},// 取消海报handleCanvasCancel() {this.$emit('canvasCancel', false);}}
};
</script><style lang="scss">
.content {text-align: center;height: 100%;
}
.canvas-content {position: fixed;left: 0;right: 0;top: 0;bottom: 0;width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;.del-icon {display: flex;width: 100%;height: 50rpx;justify-content: center;margin-top: 20rpx;> image {width: 50rpx;height: 50rpx;margin-right: 16rpx;margin-bottom: 10rpx;border-radius: 50%;}}.button-wrapper {display: flex;justify-content: center;align-items: center;width: 100%;height: 72rpx;margin-top: 15px;z-index: 16;}.save-btn {width: 40%;height: 100%;font-size: 30rpx;line-height: 72rpx;color: #fff;background: #ffbe1a;text-align: center;border-radius: 45rpx;border-radius: 36rpx;z-index: 10;}.cancel-btn {background: #fff;}.canvas-close-btn {position: fixed;width: 60rpx;height: 60rpx;padding: 20rpx;top: 30rpx;right: 0;z-index: 12;}.wisdom-dialog {.wisdom-dialog-text {display: flex;flex-direction: column;align-items: center;width: 600rpx;height: 400rpx;padding: 10px 15px;border-radius: 10px;background-color: #ffffff;border: 1px solid #f1f1f1;> text {text-align: center;font-size: 14px;margin-bottom: 30px;}.wisdom-text-title {margin-top: 15px;font-size: 16px;color: #000000;font-weight: 700;}> button {width: 80%;font-size: 15px;color: #000000;font-weight: 600;border-radius: 30px;background-color: #ffbe1a;}}}
}
</style>

使用

图片地址记得替换一下

<template><view class="mine"><view @click="isSavePic">显示</view><view class="canvas-box" v-if="isCanvas"><hchPoster ref="hchPoster" @canvasCancel="canvasCancel" :canvasAttr.sync="posterData" />         </view>   </view></template><script>
import hchPoster from '../hch-poster/hch-poster.vue';
export default {components: {hchPoster},data() {return {isCanvas: false, // 显示canvasposterData: {nickName: '兔子',handUrl: '../../static/scriptures/tim2.jpg',bgImg: '../../static/scriptures/timg.jpg',codeImg: '../../static/scriptures/qr_code.png',},};},onShow(){this.isSavePic();this.getShare()},methods: {// 检测是否有授权保存图片功能,以显示不同按钮isSavePic(){this.getShare()this.isCanvas =true;this.$nextTick(() => {this.$refs.hchPoster.posterShow();});},// 关闭海报生成弹窗canvasCancel(val) {this.isCanvas = val;},getShare(){let par = {method: 'POST',url: '接口url',status: true,show: false};this.$request(par).then(res => {if (res.data.code === '200') {this.posterData=res.data.content;}}).catch(err => {console.log(err, '获取失败');});},}
};
</script><style lang="scss">.canvas-box {position: fixed;left: 0;right: 0;top: 0;bottom: 0;width: 100%;display: flex;justify-content: flex-start;align-items: center;background-color: rgba(0, 0, 0, 0.7);z-index: 99999;}
</style>

使用时以下新建为2个文件,放在同一目录下,运行看看

uniapp 小程序 canvas海报---已封装相关推荐

  1. 小程序 canvas 海报(图片、字体封装方法)解决导出海报模糊问题

    最近真是画了一堆canvas海报画到头秃~~~(偷偷说!!产品经理我恨你!!) 来和大家分享一波本媛写的canvas方法封装 1.封装图片 //width:图片长度 //height:图片高度 //x ...

  2. H5 - 小程序Canvas海报小记

    参考文献:github-海报 小程序在wepy框架上搭建 1.在生成海报的按钮结构中引入poster: 结构: <poster id="poster" :config.syn ...

  3. uni-app小程序绘制海报

    简单版 <template><view class="poster_page"><canvas canvas-id="poster" ...

  4. uniapp/小程序 canvas画布导出图片并下载到本地

    如果微信原生的话,此处uni可以换成wx this.canvas是上一篇文章生成的canvas画布 uni.canvasToTempFilePath({// res.tempFilePath临时路径c ...

  5. 小程序canvas商品海报绘制

    小程序canvas海报绘制 1.html 绘制图片的元素 <view class="canvas-box"><canvas style="width: ...

  6. 微信小程序 canvas type = 2d 绘制海报心得(包括怎么绘制图片和圆角图片和圆角矩形等)

    微信小程序 canvas type=2d 使用心得 为了方便这里我封装成了一个component 然后说说怎么使用最新的方法(使用方法类似于html中的canvas可以进行参考)获取--canvas ...

  7. uni-app小程序使用小程序码绑定用户信息合成海报

    uni-app小程序使用小程序码绑定用户信息合成海报 需求 uni-app小程序使用小程序码绑定用户信息合成海报,小程序码绑定用户信息,和背景图片生成一张海报并保存到本地. 目标 生成目标图片 并保存 ...

  8. uniapp 小程序 APP 实现手写板 签名 画图 canvas 保存为图片格式

    文章目录 uniapp 小程序 APP 实现手写板 签名 画图 canvas 保存为图片格式 一.手写板 1.H5代码 2.JS代码 总结 uniapp 小程序 APP 实现手写板 签名 画图 can ...

  9. uniapp 微信小程序分享海报

    uniapp 微信小程序分享海报 下面是一个Uniapp微信小程序分享海报的简单示例: 在Uniapp项目中创建一个新的页面,用于展示要分享的内容和生成海报.例如,我们可以在新页面中显示一张图片和一些 ...

最新文章

  1. kettle读取不到oracle,kettle链接Oracle数据库,百试不爽!
  2. java培训学习阶段步骤讲解
  3. linux shell 计算时间差
  4. 几年前的代码发现一个BUG: 整数相除结果不能默认转换为浮点数
  5. Visual C++——《可视化编程技术》实验报告——资源的应用
  6. linux ubuntu 软件安装的三种方式
  7. C# WebBrowser自动填表与提交
  8. 2020年mysql中级课程一天一小时
  9. Internet地址结构
  10. 解决select2在bootstrap的modal中默认不显示的问题
  11. 基础连接已关闭解决办法_解决|罗技蓝牙键盘连接ipad后打不出字?
  12. 设计python游戏贪吃蛇_Python 贪吃蛇游戏
  13. Windows电脑上最好的3个txt阅读器
  14. 银行wifi认证登录怎么样
  15. 【应用安全】什么是身份和访问管理 (IAM)?
  16. 打印钻石图形python_Python pandas高效数据处理之绘图
  17. import tensorflow_addons报错
  18. 【TP5.1】树状导航栏(无极限分类)
  19. 【经验分享】大学生英语51汇听答案获取
  20. plsql中执行SELECT current_date FROM dual,为什么获取的时间不正确?获取的不是我本地的时间

热门文章

  1. 扼杀一切噪声 计讯噪音监测系统助力绿色高考
  2. 你必须要知道的九种浏览器端缓存
  3. [AI]算法小抄-State of GPT (Andrej Karpthy MSBuild2023 )
  4. python对浏览器的常用操作_python+selenium(4)--浏览器操作的基本方法
  5. Nova create instnace
  6. nodejs+vue婚庆服务网站的设计与实现
  7. 可调用输入法的远程终端桌面
  8. mac mysql 端口被占用_Mysql3306端口被占用无法启动解决办法
  9. 利用Python制作一个类似万能钥匙的小程序,轻松获取超高网速
  10. react 高阶组件hoc使用