在微信小程序中生成一张分享海报?

前言

因产品需求,需要在小程序中生成一张分享海报用于产品推广。特此记录一波产出过程~

这次开发使用的是  uni-app 来产出小程序

Part.1  大致思路

按照设计图将所需元素全部画入 Canvas 画布,再利用 wx.canvasToTempFilePath(Object object, Object this)  API 将 Canvas 生成一张指定大小的图片,保存分享即可~

此API具体用法和注意事项可去 https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.canvasToTempFilePath.html 查看

Part.2  遇到的问题

1. 由于此次 Canvas 中的内容不是固定的,可能会有很多内容。所以第一个遇到的问题就是: Canvas 中的文字换行

2. 文字换行成功后又遇到一个新问题:需要换行的文字中 不能包含空格字符,否则内容排版会错乱

3. 由于可能出现内容很多,不可控的情况,所以 Canvas 的高度也不好确定 :  Canvas 高度不确定

4. 使用网络图片画入 Canvas 中

5. 产出的 Canvas  图片模糊不清

Part.3  解决问题

问题一: 解决 Canvas  文字换行的方法

// canvas  文本换行绘制
        drawtext(ctx, t, x, y, w, num) {
            //参数说明
                //ctx:canvas的 2d 对象,t:绘制的文字,x,y:文字坐标,w:文字最大宽度
                let chr = t.split("");
                let temp = "";
                let row = [];

                for (let a = 0; a<chr.length;a++) {
                    if(ctx.measureText(temp).width < w && ctx.measureText(temp+(chr[a])).width <= w){
                        temp += chr[a];
                    }else{
                        row.push(temp);
                        temp = chr[a];
                    }
                };

                row.push(temp);
                let rowLength = row.length;

                if (num == 1) {
                    this.titleLineH = (rowLength + 1) * uni.upx2px(48);
                } else {
                    this.contentLineH = (rowLength + 1) * uni.upx2px(48);
                };

                for (let b = 0; b < rowLength; b++){
                    ctx.fillText(row[b], x, y + (b + 1) * uni.upx2px(48));//每行字体y坐标间隔24
                }
        },

问题二:利用 xxx.replace(/\s/g, ""),去掉内容中的空格字符

问题三: Canvas 高度设置为动态, 例:height: 5000px

问题四: 使用网络图片画入时,需先使用  uni.getImageInfo 这个API加载图片完成拿到临时地址后再绘入  Canvas ,否则很容易造成 Canvas 出现空白

问题五: 产出的 Canvas  图片模糊,只需将输出值扩大原来的两倍即可 ,如:200px 输出就为 400px

Part.4  代码展示

HTML

 1 <template>
 2     <view class="layout-bg">
 3
 4         <view class="scroll-Y">
 5
 6             <canvas canvas-id=‘share‘
 7                     class="canvas-style"
 8                     :style="{height: canvasHeight + ‘px‘}"></canvas>
 9
10              <view class="img-box">
11                   <image class="img-placard"
12                          :style="{height: canvasHeight + ‘px‘}"
13                          @load="placardLoad()"
14                          :src="src"></image>
15               </view>
16
17               <view :style="{height: canvasHeight + 100 + ‘px‘}"></view>
18          </view>
19
20
21          <view class="footer-btn">
22              <view class="row footer-left-box" hover-class="hover-active" @click="downloadWay()">
23                  <image class="btn-img preserve-ico"
24                        src="../../static/image/download-ico.svg"></image>
25                 <button class="btn-text  preserve-btn"
26                        :class="text == ‘长按上方图片即可保存‘? ‘text-color‘ : ‘‘">{{text}}</button>
27              </view>
28
29              <view class="btn-share-box row" hover-class="hover-active">
30                  <image class="btn-img share-ico"
31                        src="../../static/image/share-ico.svg"></image>
32                 <button class="btn-text share-btn" open-type="share">分享</button>
33              </view>
34          </view>
35     </view>
36 </template>

JS

<script>

export default {
    data() {
        return {
            src: ‘‘,
            obj: {},
            content: ‘‘,

            simpleMsgTitle: ‘标题‘,
            simpleMsgTime: ‘2019-11-23 17:20‘,

            textTitle: ‘中振区块链技术全球战略合作媒体‘,
            textDesc: ‘扫码查询获取更多资讯‘,

            text: ‘‘,

            canvasHeight: 5000, // canvas 默认高度        

            canvasStatus: false,

            query: {}
        }
    },
    onLoad(event) {
        // #ifdef MP-WEIXIN
        uni.showLoading({
            title: ‘加载中‘
        });

        this.text = ‘下载分享海报‘
        // #endif

       try {
           this.obj = JSON.parse(decodeURIComponent(event.query));
       } catch (error) {
           this.obj = JSON.parse(event.query);
       };

       uni.setNavigationBarTitle({
           title: "快讯"
       });    

       this.query = this.obj;

        this.simpleMsgTitle = this.obj.title;
        this.simpleMsgTime = this.obj.datetime;
        this.content = this.obj.content;
    },
    onReady() {
         // 开始绘制海报
         this.setCanvas()
    },
    onShareAppMessage(res) {
        return {
            title: this.query.title,
            path: ‘/pages/simpleMsg/share?query=‘ + encodeURIComponent(JSON.stringify(this.query))
        }
    },
    methods: {
         // 开始绘制海报
        setCanvas() {
            // 判断图片是否加载完成
            let imgArr = [‘https://qdksm.zhongzhenbc.com/banner.png‘,
                          ‘https://qdksm.zhongzhenbc.com/qdCode.png‘];

                uni.getImageInfo({
                    src: imgArr[0],
                    success: (img1)=> {
                        if (img1.path !== ‘‘) {
                            uni.getImageInfo({
                                src: imgArr[1],
                                success: (img2)=> {
                                    if (img2.path !== ‘‘) {
                                        const ctx = wx.createCanvasContext(‘share‘, this);
                                        ctx.fillStyle = "#2C3339";
                                        ctx.fillRect(0, 0, uni.upx2px(672), this.canvasHeight);
                                        ctx.drawImage(img1.path, 0, 0, uni.upx2px(672), uni.upx2px(202));  // h: 202
                                        ctx.setFontSize(uni.upx2px(24));
                                        ctx.setFillStyle(‘rgba(79,234,207,1)‘);
                                        ctx.fillText(‘快讯‘, uni.upx2px(30), uni.upx2px(249));
                                        ctx.setFontSize(uni.upx2px(36));
                                        ctx.setFillStyle(‘rgba(255,255,255,1)‘);
                                        ctx.fillText(‘奇点科商美‘, uni.upx2px(110), uni.upx2px(90));
                                        ctx.setFontSize(uni.upx2px(24));
                                        ctx.fillText(‘科技商业美学引领者‘, uni.upx2px(110), uni.upx2px(120));
                                        ctx.fillText(‘一站式前沿科技精英社区‘, uni.upx2px(110), uni.upx2px(150));
                                        ctx.setFontSize(uni.upx2px(32));
                                        this.drawtext(ctx, this.obj.title, uni.upx2px(30), uni.upx2px(259), uni.upx2px(612), 1)
                                        ctx.setFontSize(uni.upx2px(24));
                                        ctx.setFillStyle(‘rgba(105,117,130,1)‘);
                                        ctx.fillText(this.obj.datetime, uni.upx2px(30), uni.upx2px(269) + this.titleLineH);
                                        ctx.setFontSize(uni.upx2px(28));
                                        ctx.setFillStyle(‘rgba(244,244,244,1)‘);
                                        this.drawtext(ctx, "       "+this.obj.content.replace(/\s/g, ""), uni.upx2px(30), uni.upx2px(279) + this.titleLineH, uni.upx2px(612), 2);
                                        ctx.moveTo (0, this.titleLineH + this.contentLineH + uni.upx2px(289));       //设置起点状态
                                        ctx.lineTo (uni.upx2px(672), this.titleLineH + this.contentLineH + uni.upx2px(289));       //设置末端状态
                                        ctx.drawImage(img2.path, uni.upx2px(30), this.titleLineH + this.contentLineH + uni.upx2px(315), uni.upx2px(160), uni.upx2px(160));
                                        ctx.setFontSize(uni.upx2px(24));
                                        ctx.setFillStyle(‘rgba(79,234,207,1)‘);
                                        ctx.fillText(‘中振区块链技术全球战略合作媒体‘, uni.upx2px(272), this.titleLineH + this.contentLineH + uni.upx2px(362));
                                        ctx.setFillStyle(‘rgba(255,255,255,1)‘);
                                        ctx.fillText(‘扫码查询获取更多资讯‘, uni.upx2px(392), this.titleLineH + this.contentLineH + uni.upx2px(412));

                                        this.canvasHeight = this.titleLineH + this.contentLineH + uni.upx2px(511); // 根据内容高度重新为 canvas 赋值高度

                                        ctx.lineWidth = 1;          //设置线宽状态
                                        ctx.strokeStyle = "#697582" ;  //设置线的颜色状态
                                        ctx.stroke();
                                        ctx.draw(true, ()=> {
                                            uni.canvasToTempFilePath({
                                              x: 0,
                                              y: 0,
                                              width: uni.upx2px(672),
                                              height: this.canvasHeight,
                                              destWidth: uni.upx2px(1244),
                                              destHeight: this.canvasHeight * 2,
                                              canvasId: ‘share‘,
                                              success: (res)=> {
                                                  this.src = res.tempFilePath;
                                                  this.canvasStatus = true
                                              },fail(err) {
                                                  console.log(err)
                                              }
                                            },this)
                                        },200);
                                    }
                                }
                            })
                        }
                    }
                })
        },

        // canvas  文本换行绘制
        drawtext(ctx, t, x, y, w, num) {
            //参数说明
                //ctx:canvas的 2d 对象,t:绘制的文字,x,y:文字坐标,w:文字最大宽度
                let chr = t.split("");
                let temp = "";
                let row = [];

                for (let a = 0; a<chr.length;a++) {
                    if(ctx.measureText(temp).width < w && ctx.measureText(temp+(chr[a])).width <= w){
                        temp += chr[a];
                    }else{
                        row.push(temp);
                        temp = chr[a];
                    }
                };

                row.push(temp);
                let rowLength = row.length;

                if (num == 1) {
                    this.titleLineH = (rowLength + 1) * uni.upx2px(48);
                } else {
                    this.contentLineH = (rowLength + 1) * uni.upx2px(48);
                };

                for (let b = 0; b < rowLength; b++){
                    ctx.fillText(row[b], x, y + (b + 1) * uni.upx2px(48));//每行字体y坐标间隔24
                }
        },

        // 海报加载完成事件
        placardLoad() {
            uni.hideLoading();
        },

        // 保存海报
        downloadWay() {
            let that = this;

            // #ifdef H5
             that.text = ‘长按上方图片即可保存‘;
            // #endif

            // #ifdef MP-WEIXIN
            that.text = ‘下载分享海报‘;

            uni.authorize({
                scope: ‘scope.writePhotosAlbum‘,
                success() {
                   uni.saveImageToPhotosAlbum({
                       filePath: that.src,
                       success: function() {
                           uni.showModal({
                               title: ‘保存成功‘,
                               content: ‘已保存到相册,快去看看吧‘,
                               showCancel: false
                           })
                       }
                   })
                },fail:function() {
                    uni.showModal({
                      title: ‘提示‘,
                      content: ‘您点击了拒绝授权,将无法正常保存图片,点击确定可重新获取授权‘,
                      success: function (res) {
                        if (res.confirm) {
                          uni.openSetting({
                            success: (res) => {
                              if (res.authSetting["scope.writePhotosAlbum"]) {////如果用户重新同意了授权登录
                                uni.saveImageToPhotosAlbum({
                                    filePath: that.src,
                                    success: function() {
                                        uni.showModal({
                                            title: ‘保存成功‘,
                                            content: ‘已保存到相册,快去看看吧‘,
                                            showCancel: false
                                        })
                                    }
                                })
                              }
                            }, fail: function (res) {}
                          })
                        }
                      }
                    })
                 }
            })
            // #endif
        }
    }
}
</script>

CSS

<style scoped>

button::after{
    border: none
}
.scroll-Y {
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
}
 .canvas-style, .img-box {
     position: absolute;
     top: 40upx;
}
.canvas-style {
    width: 672upx;
    top: -9999rpx
}
.position-absolute {
    position: absolute;
}
.footer-btn, .row {
    flex-direction: row;
}
.row {
    z-index: 9999;
}
.layout-bg {
    background-color: #20252B;
}

.footer-btn {
    width: 100%;
    height: 100upx;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background-color: #2C3339;
    z-index: 9999;
}

.footer-left-box, .btn-share-box{
    width: 50%;
    height: 100upx;
    align-items: center;
    justify-content: center;
    border-radius: 10upx;
    position: relative;
}
.btn-img {
    width: 40upx;
    height: 40upx;
    position: absolute;
    top: 30upx
}
.preserve-ico {
    left: 89upx;
}
.share-ico {
    left: 138upx;
}
.btn-text {
    font-size: 24upx;
    font-weight:400;
    color:rgba(105,117,130,1);
    background-color: transparent;
}
.download-img {
    margin-left: 88upx;
}
.btn-download-box2 {
    width: 100%;
    justify-content: center;
}
.download-img2 {
    margin-left: 0upx;
}

.img-box,.img-placard {
    z-index: 998;
}
.share-btn,.preserve-btn {
    width: 100%;
    height: 100rpx;
    font-size: 24rpx;
    font-weight: 400;
    color: rgba(105,117,130,1);
    background-color: transparent;
    padding-left: 50upx;
    padding-right: 0;
    line-height: 104upx;
}
.hover-active {
    opacity: 0.9;
    background: #20252B;
}
.text-color {
    color:rgba(79,234,207,1);
}
.img-placard {
    width: 672upx;
    border-radius: 10upx;
    box-shadow: 0px 1px 3px rgba(34, 25, 25, 0.2);
}
button {
    padding-left: 0;
    padding-right: 60upx;
}
</style>

原文地址:https://www.cnblogs.com/langxiyu/p/12693280.html

时间: 2024-11-06 16:00:18

在微信小程序中生成一张分享海报?的相关文章

在微信小程序中使用LeanCloud(一)

之前学习了微信小程序前端,使用到LeanCloud线上数据库 [传送门].作为一个前端开发人员,了解后端及数据库是学习工作的需要. LeanCloud直接登录,未注册直接创建账户.它是一款免费的线上数据库(开发版免费).适用于一些想自己写微信小程序前端但不太会后端的开发者学习用.本篇文章涉及数据存储服务(增删查改). 首先,下载一个JavaScript-sdk :av-weapp-min.js[下载链接],它是在微信小程序中使用此数据库的关键文件.下载之后,保存至项目路径,这里以'/libs/a

微信小程序动态生成保存二维码

起源:最近小程序需要涉及到一些推广方面的功能,所以要写一个动态生成二维码用户进行下载分享,写完之后受益良多,特此来分享一下: 一.微信小程序动态生成保存二维码 wxml: <canvas style="width: 350rpx;height: 350rpx;background:#f1f1f1;" canvas-id="mycanvas"/> js: // pages/qrcode/qrcode.js var QR = require("..

如何在微信小程序中使用字体图标

微信小程序中,在image标签里,可以在src中引用本地文件,但是background设置背景图或者使用字体图标的时候,却不能引用本地文件,只能用url地址的图片或字体,或者使用base64编码后的格式,图片我们可以在线转换,随便搜一下,有很多在线转换工具,但是使用字体图标的时候,怎么转换呢?下面我们记录一下使用图标字体的l两个方法.    方法一:将字体url转换为base64的格式后使用 第一步,下载需要的字体图: 打开阿里巴巴矢量图标库,选择自己需要的图标添加到购物车,然后点击购物车下载代

微信小程序中target与currentTarget

如有错误,请纠出,大家一起进步!!! target在事件流的目标阶段:currentTarget在事件流的捕获,目标及冒泡阶段.但事件流处于目标阶段,target与currentTarget指向一样, 而当处于捕获和冒泡阶段的时候,target指向被单击的对象而currentTarget指向当前事件活动的对象.在微信小程序中也可总结为:target指向发生事件的组件,currentTarget指向绑定事件的组件. 下面请看例子: text.wxml: <view class="view1&

微信小程序中的 hover-class

微信小程序中,可以用 hover-class 属性来指定元素的点击态效果.但是在在使用中要注意,大部分组件是不支持该属性的. 目前支持 hover-class 属性的组件有三个:view.button.navigator. 不支持 hover-class 属性的组件,同时也不支持 hover-stop-propagation.hover-start-time.hover-stay-time 这三个属性. 使用方法: <view hover-class="bg_red">这是

微信小程序中的单位

vw:viewpoint width,视窗宽度,1vw等于视窗宽度的1%. vh:viewpoint height,视窗高度,1vh等于视窗高度的1%. rpx:rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应.规定屏幕宽为750rpx.如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素. 微信小程序也支持rem尺寸单位,rem和rpx的换算关系:rem: 规

微信小程序中获取高度及设备的方法

由于js中可以采用操纵dom的方法来获取页面元素的高度,可是在微信小程序中不能操纵dom,经过查找之后发现仅仅只有以下几个方法可以获取到高度 wx.getSystemInfoSync().windowWidth // 获取当前窗口的宽度 wx.getSystemInfoSync().windowHeight // 获取当前窗口的高度 wx.getSystemInfoSync().model // 获取当前采用的设备 wx.getSystemInfoSync().pixelRatio wx.get

微信小程序中的循环遍历问题

比如:如果在微信小程序中要遍历输出 0-9 的数,我们会使用for循环 for(var i=0;i<10;i++){ console.log(i); } 确实结果也是这样: 但是,如果我在循环时同时调用wx的api接口10次,那么输出的结果就会不同(这是产生了闭关的效应) eg:每次调用一次wx.showToast()接口,并在成功时输出循环的值. for(var i=0;i<10;i++){ wx.showToast({ title: 'haha', success:function(){

微信小程序中使用ECharts 异步加载数据 实现图表

<!--pages/bar/index.wxml--> <view class="container"> <ec-canvas id="mychart-dom-bar" canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas> </view> import * as echarts from '../../ec-canvas