前端生成分享海報(bào)兼容H5和小程序

移動(dòng)端分享海報(bào)生成

最近做項(xiàng)目需求是生成商品分享海報(bào)舱权,并且保存到手機(jī)中要兼容H5和小程序

與后端同學(xué)溝通后,海報(bào)在前端生成最省性能和有較好的交互體驗(yàn)涯雅,先看做好的效果

Mar-16-2021 14-07-57.gif
Mar-16-2021 14-08-45.gif

前端框架使用的是uni-app方便打包成H5和小程序
實(shí)現(xiàn)方案是拿到后端返回的數(shù)據(jù)后夺欲,利用canvas畫(huà)布把各個(gè)數(shù)據(jù)拼在一起并且生成一張圖片
主要的參數(shù)有:背景圖媒至、商品圖、二維碼季二、價(jià)格檩咱、原價(jià)、標(biāo)題

首先拿到產(chǎn)品圖和二維碼之后需要把它們下載下來(lái)用uni-app的api就可以
先寫(xiě)一個(gè)下載方法并且在template 定義畫(huà)布組件

<template>
<canvas class="canvas" canvas-id="myCanvas" v-if="canvasStatus"></canvas>
</template>
onReady(){
  this.downloadFileImg('','pic');
  this.downloadFileImg('','code');
},
methods:{
  downloadFileImg(url,name){
    let self = this
    uni.downloadFile({
      url: url,
      success: function(res) {
        self[name] = res.tempFilePath;
      },
      fail: function(erros) {
        console.log(error)
      }
    });
  }
}

這樣圖片就暫時(shí)保存到本地臨時(shí)文件了

uni.downloadFile 需要注意的是
在各個(gè)小程序平臺(tái)運(yùn)行時(shí)胯舷,網(wǎng)絡(luò)相關(guān)的 API 在使用前需要配置域名白名單刻蚯。在h5上是跨域的,用戶需要處理好跨域問(wèn)題桑嘶。

下來(lái)編寫(xiě)canvas生成圖片的方法

/**
    * 獲取分享海報(bào)
    * @param array imgArr 海報(bào)素材 0 背景圖 1商品圖 2二維碼
    * @param string store_name 素材文字
    * @param string price 價(jià)格
    * @param string ot_price 原始價(jià)格
    * @param function successFn 回調(diào)函數(shù)
*/
PosterCanvas: function(imgArr, store_name, price, ot_price, successFn) {
    let that = this;
    uni.showLoading({
        title: '海報(bào)生成中',
        mask: true
    });
    const ctx = uni.createCanvasContext('myCanvas');
    ctx.clearRect(0, 0, 0, 0);

    /**
    * 只能獲取合法域名下的圖片信息,本地調(diào)試無(wú)法獲取
    * 
    */
    ctx.fillStyle = '#fff';
    ctx.fillRect(0, 0, 750, 1150);
    uni.getImageInfo({
        src: imgArr[0],
        success: function(res) {
            const WIDTH = res.width;
            const HEIGHT = res.height;
            ctx.drawImage(imgArr[1], 0, 0, WIDTH, WIDTH);
            ctx.save();
            let r = 110;
            let d = r * 2;
            let cx = 480;
            let cy = 790;
            ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI);
            // ctx.clip();
            ctx.drawImage(imgArr[2], cx, cy, d, d);
            ctx.restore();
            const CONTENT_ROW_LENGTH = 20;
            let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name, CONTENT_ROW_LENGTH);
            if (contentRows > 2) {
                contentRows = 2;
                let textArray = contentArray.slice(0, 2);
                textArray[textArray.length - 1] += '……';
                contentArray = textArray;
            }
            ctx.setTextAlign('left');
            ctx.setFontSize(36);
            ctx.setFillStyle('#000');
            // let contentHh = 36 * 1.5;
            let contentHh = 36;
            for (let m = 0; m < contentArray.length; m++) {
                if (m) {
                    ctx.fillText(contentArray[m], 50, 1000 + contentHh * m + 18, 1100);
                } else {
                    ctx.fillText(contentArray[m], 50, 1000 + contentHh * m, 1100);
                }
            }
            ctx.setTextAlign('left')
            ctx.setFontSize(72);
            ctx.setFillStyle('#DA4F2A');
            ctx.fillText('¥' + price, 40, 820 + contentHh);

            ctx.setTextAlign('left')
            ctx.setFontSize(36);
            ctx.setFillStyle('#999');
            ctx.fillText('¥' + ot_price, 50, 876 + contentHh);
            var underline = function(ctx, text, x, y, size, color, thickness, offset) {
                var width = ctx.measureText(text).width;
                switch (ctx.textAlign) {
                    case "center":
                        x -= (width / 2);
                        break;
                    case "right":
                        x -= width;
                        break;
                }

                y += size + offset;
                ctx.beginPath();
                ctx.strokeStyle = color;
                ctx.lineWidth = thickness;
                ctx.moveTo(x, y);
                ctx.lineTo(x + width, y);
                ctx.stroke();
            }
            underline(ctx, '¥' + ot_price, 55, 865, 36, '#999', 2, 0)
            ctx.setTextAlign('left')
            ctx.setFontSize(28);
            ctx.setFillStyle('#999');
            ctx.fillText('長(zhǎng)按或掃描查看', 490, 1030 + contentHh);
            ctx.draw(true, function() {
                uni.canvasToTempFilePath({
                    canvasId: 'myCanvas',
                    fileType: 'png',
                    destWidth: WIDTH,
                    destHeight: HEIGHT,
                    success: function(res) {
                        uni.hideLoading();
                        successFn && successFn(res.tempFilePath);
                    }
                })
            });
        },
        fail: function(err) {
            uni.hideLoading();
            that.Tips({
                title: '無(wú)法獲取圖片信息'
            });
        }
    })
},

首先創(chuàng)建一個(gè)canvas畫(huà)布

獲取背景圖圖片信息拿到寬和高再繪制商品圖片并保存

接下來(lái)繪制二維碼并把坐標(biāo)放好并保存

在處理文字換行問(wèn)題并設(shè)置大小顏色和對(duì)其方式

在相對(duì)應(yīng)的設(shè)置價(jià)格和原價(jià)的顏色和大小還有坐標(biāo)

由于價(jià)格還有條橫線炊汹,我在網(wǎng)上又搜下了橫線的做法直接看方法就行

最后生成圖片信息并且使用uni.canvasToTempFilePath 方法把當(dāng)前畫(huà)布指定區(qū)域的內(nèi)容導(dǎo)出生成指定大小的圖片,并返回文件路徑逃顶。

這樣我們就得到一個(gè).png的臨時(shí)文件現(xiàn)在就剩最后一步把文件渲染到組件里了讨便,從回調(diào)函數(shù)就可以回去到

此方法用的比方比較多我把它寫(xiě)到公共方法里面并且綁定到vue原型上面方便我們后面使用

現(xiàn)在編寫(xiě)方法調(diào)用

handelCanvas(){
    let imgArr = ['背景圖路徑',this.pic,this.code]
    this.$util.PosterCanvas(imgArr,'標(biāo)題','價(jià)格','原價(jià)',function(tempFilePath){
        console.log(tempFilePath)
    })
}

這樣就拿到生成好的圖片的是一個(gè)臨時(shí)文件 現(xiàn)在把他放到頁(yè)面中展示就ok了
保存圖片功能H5可以長(zhǎng)按保存圖片這里只用處理小程序的就行
首先檢測(cè)授權(quán)拿到授權(quán)后調(diào)用uni-app的api就可以了

savePosterPath: function() {
    let that = this;
    uni.getSetting({
        success(res) {
            if (!res.authSetting['scope.writePhotosAlbum']) {
                uni.authorize({
                    scope: 'scope.writePhotosAlbum',
                    success() {
                        uni.saveImageToPhotosAlbum({
                            filePath: 'canvas生成的臨時(shí)圖片',
                            success: function(res) {
                                ....成功了
                            },
                            fail: function(res) {
                                ....失敗了
                            }
                        });
                    }
                });
            } else {
                uni.saveImageToPhotosAlbum({
                    filePath: 'canvas生成的臨時(shí)圖片',
                    success: function(res) {
                        ....成功了
                    },
                    fail: function(res) {
                        ....失敗了
                    }
                });
            }
        }
    });
},

這樣前端生成海報(bào)就大功告成了充甚,你學(xué)廢了嗎?

最后打一波廣告:

CRMEB商城一個(gè)免費(fèi)開(kāi)源項(xiàng)目

移動(dòng)端使用uni-app框架目前已經(jīng)適配公眾號(hào)霸褒、小程序伴找、app(暫未發(fā)布)

管理后臺(tái)使用vue+iview框架

開(kāi)源不易,希望各位關(guān)注下废菱,說(shuō)不定你會(huì)有意外收獲技矮!

地址:http://github.crmeb.net/u/qiang

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市殊轴,隨后出現(xiàn)的幾起案子衰倦,更是在濱河造成了極大的恐慌,老刑警劉巖旁理,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件樊零,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡韧拒,警方通過(guò)查閱死者的電腦和手機(jī)淹接,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)叛溢,“玉大人塑悼,你說(shuō)我怎么就攤上這事】簦” “怎么了厢蒜?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)烹植。 經(jīng)常有香客問(wèn)我斑鸦,道長(zhǎng),這世上最難降的妖魔是什么草雕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任巷屿,我火速辦了婚禮,結(jié)果婚禮上墩虹,老公的妹妹穿的比我還像新娘嘱巾。我一直安慰自己,他們只是感情好诫钓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布旬昭。 她就那樣靜靜地躺著,像睡著了一般菌湃。 火紅的嫁衣襯著肌膚如雪问拘。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音骤坐,去河邊找鬼绪杏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛或油,可吹牛的內(nèi)容都是我干的寞忿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼顶岸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼腔彰!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起辖佣,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤霹抛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后卷谈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體杯拐,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年世蔗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了端逼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡污淋,死狀恐怖顶滩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寸爆,我是刑警寧澤礁鲁,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站赁豆,受9級(jí)特大地震影響仅醇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魔种,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一析二、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧节预,春花似錦甲抖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挫剑。三九已至去扣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背愉棱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工唆铐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奔滑。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓艾岂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親朋其。 傳聞我的和親對(duì)象是個(gè)殘疾皇子王浴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容