uniapp 小程序 canvas海报---已封装
已封装好的代码
<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海报---已封装相关推荐
- 小程序 canvas 海报(图片、字体封装方法)解决导出海报模糊问题
最近真是画了一堆canvas海报画到头秃~~~(偷偷说!!产品经理我恨你!!) 来和大家分享一波本媛写的canvas方法封装 1.封装图片 //width:图片长度 //height:图片高度 //x ...
- H5 - 小程序Canvas海报小记
参考文献:github-海报 小程序在wepy框架上搭建 1.在生成海报的按钮结构中引入poster: 结构: <poster id="poster" :config.syn ...
- uni-app小程序绘制海报
简单版 <template><view class="poster_page"><canvas canvas-id="poster" ...
- uniapp/小程序 canvas画布导出图片并下载到本地
如果微信原生的话,此处uni可以换成wx this.canvas是上一篇文章生成的canvas画布 uni.canvasToTempFilePath({// res.tempFilePath临时路径c ...
- 小程序canvas商品海报绘制
小程序canvas海报绘制 1.html 绘制图片的元素 <view class="canvas-box"><canvas style="width: ...
- 微信小程序 canvas type = 2d 绘制海报心得(包括怎么绘制图片和圆角图片和圆角矩形等)
微信小程序 canvas type=2d 使用心得 为了方便这里我封装成了一个component 然后说说怎么使用最新的方法(使用方法类似于html中的canvas可以进行参考)获取--canvas ...
- uni-app小程序使用小程序码绑定用户信息合成海报
uni-app小程序使用小程序码绑定用户信息合成海报 需求 uni-app小程序使用小程序码绑定用户信息合成海报,小程序码绑定用户信息,和背景图片生成一张海报并保存到本地. 目标 生成目标图片 并保存 ...
- uniapp 小程序 APP 实现手写板 签名 画图 canvas 保存为图片格式
文章目录 uniapp 小程序 APP 实现手写板 签名 画图 canvas 保存为图片格式 一.手写板 1.H5代码 2.JS代码 总结 uniapp 小程序 APP 实现手写板 签名 画图 can ...
- uniapp 微信小程序分享海报
uniapp 微信小程序分享海报 下面是一个Uniapp微信小程序分享海报的简单示例: 在Uniapp项目中创建一个新的页面,用于展示要分享的内容和生成海报.例如,我们可以在新页面中显示一张图片和一些 ...
最新文章
- kettle读取不到oracle,kettle链接Oracle数据库,百试不爽!
- java培训学习阶段步骤讲解
- linux shell 计算时间差
- 几年前的代码发现一个BUG: 整数相除结果不能默认转换为浮点数
- Visual C++——《可视化编程技术》实验报告——资源的应用
- linux ubuntu 软件安装的三种方式
- C# WebBrowser自动填表与提交
- 2020年mysql中级课程一天一小时
- Internet地址结构
- 解决select2在bootstrap的modal中默认不显示的问题
- 基础连接已关闭解决办法_解决|罗技蓝牙键盘连接ipad后打不出字?
- 设计python游戏贪吃蛇_Python 贪吃蛇游戏
- Windows电脑上最好的3个txt阅读器
- 银行wifi认证登录怎么样
- 【应用安全】什么是身份和访问管理 (IAM)?
- 打印钻石图形python_Python pandas高效数据处理之绘图
- import tensorflow_addons报错
- 【TP5.1】树状导航栏(无极限分类)
- 【经验分享】大学生英语51汇听答案获取
- plsql中执行SELECT current_date FROM dual,为什么获取的时间不正确?获取的不是我本地的时间
热门文章
- 扼杀一切噪声 计讯噪音监测系统助力绿色高考
- 你必须要知道的九种浏览器端缓存
- [AI]算法小抄-State of GPT (Andrej Karpthy MSBuild2023 )
- python对浏览器的常用操作_python+selenium(4)--浏览器操作的基本方法
- Nova create instnace
- nodejs+vue婚庆服务网站的设计与实现
- 可调用输入法的远程终端桌面
- mac mysql 端口被占用_Mysql3306端口被占用无法启动解决办法
- 利用Python制作一个类似万能钥匙的小程序,轻松获取超高网速
- react 高阶组件hoc使用