微信分享图片组件(小程序 )

效果图.png

需求:点击分享,弹出遮罩层,可分享给好友,可保存图片分享,canvas中的图片自适应(缩放、裁剪)
技术:canvas 2,vant-weapp-ui
思路:计划将整个分享都写成一个自定义组件,由于一些bug,没能实现,部分还是需要写在页面中。

share组件:
share.wxml


    
        
            
            
                
        
    

share.js 含有canvas绘制白色背景,canvas文本换行,绘制图片,图片原比例缩小裁剪,图片自适应,保存图片等方法

import {request} from "../../common/httpService"; 

const app = getApp()

Component({
    /**
     * 组件的属性列表
     */
    properties: {
        type: {
            type: String,
            value: ''
        },
        shareWords: {
            type: String,
            value: ''
        },
        imgSrc: {
            type: String,
            value: ''
        },
        title: {
            type: String,
            value: ''
        },
        userName: {
            type: String,
            value: ''
        },
        product: {
            type: Object,
            value: {}
        },
        dec: {
            type: String,
            value: ''
        },
        link: {
            type: String,
            value: ''
        },
        sceneStr: {
            type: String,
            value: ''
        },
        articleName: {
            type: String,
            value: ''
        }
    },

    /**
     * 组件的初始数据
     */
    data: {
        showShare: false,
        referrer: wx.getStorageSync('userId'),
        canvas: null
    },
    ready: function () {
        if (this.properties.type === 'article') {
            this.createArticlePic()
        } else if (this.properties.type === 'invited') {
            this.createInvitePic()
        } else if (this.properties.type === 'product') {
            this.createProductPic()
        }
        // this.getCodeImg()
    },


    /**
     * 组件的方法列表
     */
    methods: {
        initCanvas() {
            return new Promise((resolve, reject) => {
                const query = wx.createSelectorQuery()
                query.select('#myCanvas')
                    .fields({
                        node: true,
                        size: true,
                        id: true
                    })
                    .exec((res) => {
                        const canvas = res[0].node
                        const ctx = canvas.getContext('2d')
                        this.setData({
                            canvas: canvas
                        })
                        const dpr = wx.getSystemInfoSync().pixelRatio
                        canvas.width = res[0].width * dpr
                        canvas.height = res[0].height * dpr
                        ctx.scale(dpr, dpr)
                        let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                        console.log('imageData', imageData)
                        for (let i = 0; i < imageData.data.length; i += 4) {
                            if (imageData.data[i + 3] === 0) {
                                imageData.data[i] = 255;
                                imageData.data[i + 1] = 255;
                                imageData.data[i + 2] = 255;
                                imageData.data[i + 3] = 255;
                            }
                        }
                        ctx.putImageData(imageData, 0, 0);
                        let data = {
                            ctx,
                            canvas: res[0]
                        }
                        return resolve(data)
                    })
            })
        },
        createArticlePic() {
            let that = this
            that.initCanvas().then((data) => {
                const ctx = data.ctx
                const canvasInfo = data.canvas
                const canvas = that.data.canvas
                let pic = that.properties.imgSrc
                if (!that.properties.imgSrc) {
                    pic = '../../images/share-article-bg.png'
                }
                let cW = canvasInfo.width * 0.91
                let cH = canvasInfo.height * 0.56
                console.log('cW', cW)
                console.log('cH', cH)
                that.drawArticlePic(ctx, canvas, cW, cH, pic).then(res => {
                    console.log('画入成功')
                    ctx.fillStyle = 'rgba(0,0,0,0.5)'
                    ctx.fillRect(15, 95, cW, cH)
                    ctx.fillStyle = '#333333'
                    ctx.font = '18px PingFang'
                    let title = that.properties.articleName
                    console.log('文章title', title)
                    if (!title) {
                        if (that.properties.dec.length < 10) {
                            title = that.properties.dec
                        } else {
                            title = that.properties.dec.slice(0, 10) + '...'
                        }
                    }
                    ctx.fillText(title, 15, 50)
                    ctx.fillStyle = '#aaa'
                    ctx.font = '14px PingFang'
                    ctx.fillText(`来自${that.properties.userName}的邀请`, 15, 80)
                    ctx.fillStyle = '#ffffff'
                    ctx.font = '14px PingFang'
                    ctx.fillText(`123人已浏览`, 30, 288)
                    wx.canvasToTempFilePath({
                        canvasId: 'myCanvas',
                        canvas: canvas,
                        fileType: 'png',
                        success: function (res) {
                            console.log('canvas生成图片')
                            console.log(res.tempFilePath)
                            that.setData({
                                canvasPicPath: res.tempFilePath
                            })
                        },
                        fail: function (res) {
                            console.log('canvas生成图片失败')
                            console.log(res);
                        }
                    }, that)
                })
            })
        },
        createProductPic() {
            let that = this
            that.initCanvas().then(data => {
                const ctx = data.ctx
                const canvasInfo = data.canvas
                const canvas = that.data.canvas
                let borderW = canvasInfo.width * 0.89
                let borderH = canvasInfo.height * 0.77
                let textW = canvasInfo.width * 0.81
                this.initCanvasBg(canvas, ctx, "../../images/logo.png", 25, 25, 15, 28)
                ctx.fillStyle = '#333333'
                ctx.font = '12px PingFang'
                ctx.fillText('绿植物', 49, 46)
                ctx.fillStyle = '#8E8E8E'
                ctx.font = '14px PingFang'
                ctx.fillText(`${this.properties.userName}给你推荐了一个好东西`, 20, 79)
                ctx.strokeStyle = '#EEEEEE'
                ctx.strokeRect(20, 89, borderW, borderH)
                that.initCanvasBg(canvas, ctx, this.properties.imgSrc, 163, 163, 84, 98)
                ctx.fillStyle = '#CF1322'
                ctx.font = '24px PingFang'
                ctx.fillText('¥' + this.properties.product.vipPrice, 27, 288)
                ctx.fillStyle = '#AAAAAA'
                ctx.font = '14px PingFang'
                ctx.fillText('¥' + this.properties.product.originPrice, 105, 288)
                //原价删除线
                ctx.beginPath()
                ctx.lineWidth = 1;
                ctx.strokeStyle = "#AAAAAA";
                ctx.moveTo(103, 283)
                ctx.lineTo(149, 283)
                ctx.stroke()
                ctx.fillStyle = '#333333'
                ctx.font = '14px PingFang'
                // ctx.fillText(that.properties.product.name, 27, 318)
                that.drawText(ctx, that.properties.product.name, 29, 293, textW);
                ctx.fillStyle = '#AAAAAA'
                ctx.font = '12px PingFang'
                // ctx.fillText(that.properties.product.fullDescription, 27, 340)
                that.drawText(ctx, that.properties.product.fullDescription, 29, 340, textW);
                // TODO 二维码
                wx.canvasToTempFilePath({
                    canvasId: 'myCanvas',
                    canvas: canvas,
                    fileType: 'png',
                    success: function (res) {
                        console.log('canvas生成图片')
                        console.log(res.tempFilePath)
                        that.setData({
                            canvasPicPath: res.tempFilePath
                        })
                    },
                    fail: function (res) {
                        console.log('canvas生成图片失败')
                        console.log(res);
                    }
                }, that)
            })
        },
        createInvitePic() {
            let that = this
            that.initCanvas().then(data => {
                const ctx = data.ctx
                const canvasInfo = data.canvas
                const canvas = that.data.canvas
                let systemWidth = app.globalData.systemWidth
                let picWidth = systemWidth * 0.8
                let picHeight = picWidth * 0.97
                this.initCanvasBg(canvas, ctx, "../../images/logo.png", 25, 25, 15, 36).then((logoSuc) => {
                    console.log('logoSuc', logoSuc)
                    this.initCanvasBg(canvas, ctx, "../../images/share-img.png", picWidth, picHeight).then((res1) => {
                        console.log('res1', res1)
                        ctx.textAlign = 'left'
                        ctx.fillStyle = '#333333'
                        ctx.font = '14px PingFang'       // 文字字号:22px
                        ctx.fillText('绿植物', 49, 56)
                        ctx.textAlign = 'center'
                        ctx.fillStyle = '#E2A02B'
                        ctx.font = '20px PingFang'       // 文字字号:22px
                        ctx.fillText('邀您成为VIP会员', canvasInfo.width / 2, 137)
                        ctx.textAlign = 'center'
                        ctx.fillStyle = '#ffffff'
                        ctx.font = '14px PingFang'       // 文字字号:22px
                        ctx.fillText(`来自${this.properties.userName}的邀请`, canvasInfo.width / 2, 160)
                        this.roundRectColor(ctx, 119, 250, 92, 22, 16, canvasInfo.width)
                        ctx.textAlign = 'center'
                        ctx.fillStyle = '#E2A02B'
                        ctx.font = '20px PingFang'       // 文字字号:22px
                        ctx.fillText('最高可享3折优惠', canvasInfo.width / 2, 325)
                        wx.canvasToTempFilePath({
                            canvasId: 'myCanvas',
                            canvas: canvas,
                            fileType: 'png',
                            success: function (res) {
                                console.log('canvas生成图片')
                                console.log(res.tempFilePath)
                                that.setData({
                                    canvasPicPath: res.tempFilePath
                                })
                            },
                            fail: function (res) {
                                console.log('canvas生成图片失败')
                                console.log(res);
                            }
                        }, that)
                    })
                })
            })
        },
        initCanvasBg(canvas, ctx, imgPath, w, h, x, y) {
            return new Promise((resolve, reject) => {
                let bgPicturePath = imgPath;//图片路径不要出错
                const img = canvas.createImage()
                img.src = bgPicturePath
                let oX = 15
                let oY = 76
                if (x) {
                    oX = x
                }
                if (y) {
                    oY = y
                }
                img.onload = () => {
                    ctx.drawImage(img, oX, oY, w, h);
                    return resolve()
                }
            })
        },
        drawArticlePic(ctx, canvas, canvas_width, canvas_height, imgPath) {
            return new Promise((resolve, reject) => {
                wx.getImageInfo({
                    src: imgPath,
                    success: function (res) {

                        let img_width = res.width,   //图片宽
                            img_height = res.height;  //图片高
                        let clip_left, clip_top, //左偏移值,上偏移值,
                            clip_width, clip_height, //截取宽度,截取高度
                            dWidth, dHeight,
                            dx, dy;
                        //  ----------------裁剪图片----------------
                        if (img_width > canvas_width && img_height > canvas_height) {    //图片宽高都大于框框
                            if (img_width / img_height > 1 || img_width / img_height === 1) {   //宽图 或正方形
                                //将图高度自适应
                                let factor = img_height / canvas_height
                                clip_width = factor * canvas_width
                                clip_height = img_height
                                clip_top = 0
                                clip_left = (img_width - clip_width) / 2  //clip_left 取中间值
                            } else if (img_width / img_height < 1) {   //长图
                                let factor = img_width / canvas_width  // 图片宽/框宽= 裁剪长度/框长
                                // img_width = canvas_width
                                clip_width = img_width
                                clip_height = factor * canvas_height
                                clip_top = (img_height - clip_height) / 2
                                clip_left = 0  //clip_left 取中间值
                            }
                            dWidth = canvas_width
                            dHeight = canvas_height
                            dx = 15
                            dy = 95
                        } else if (img_width <= canvas_width) {   //宽度小于等于框
                            dWidth = img_width
                            if (img_height >= canvas_height) {
                                dHeight = canvas_height
                                clip_top = (img_height - canvas_height) / 2  //裁掉多余的高
                                dy = 0    //起始位置
                            } else {
                                dHeight = img_height
                                dy = (canvas_height - img_height) / 2
                                clip_top = 0
                            }
                            dx = 0
                            clip_left = 0

                        } else if (img_height <= canvas_height) {  //高度小于等于框
                            dHeight = img_height
                            if (img_width >= canvas_width) {
                                dWidth = canvas_width
                                dx = 0
                                clip_left = (img_width - canvas_width) / 2
                            } else {
                                dWidth = img_width
                                dx = (canvas_width - img_width) / 2
                                clip_left = 0
                            }
                            dy = 0
                            clip_top = 0
                        }
                        const img = canvas.createImage()
                        img.src = imgPath
                        img.onload = (res) => {
                            console.log('img_load', res)
                            ctx.drawImage(img, clip_left, clip_top, clip_width, clip_height, dx, dy, dWidth, dHeight);
                            return resolve()
                        }
                    }
                })
            })
        },
        roundRectColor(context, x, y, w, h, r, canvasWidth) {  //绘制圆角矩形(纯色填充)
            context.save();
            context.fillStyle = '#3B3B3B';
            context.strokeStyle = '#3B3B3B'
            context.lineJoin = 'round';  //交点设置成圆角
            context.lineWidth = r;
            context.strokeRect(x + r / 2, y + r / 2, w - r, h - r);
            context.fillRect(x + r, y + r, w - r * 2, h - r * 2);
            context.stroke();
            context.closePath();
            context.textAlign = 'center'
            context.fillStyle = '#ffffff'
            context.font = '10px PingFang'       // 文字字号:22px
            context.fillText('长按扫码加入', canvasWidth / 2, 265)
        },
        savePic() {
            let canvasPicPath = this.data.canvasPicPath
            console.log('canvasPicPath', canvasPicPath)
            wx.saveImageToPhotosAlbum({
                filePath: canvasPicPath,
                success(res) {
                    console.log('保存成功', res)
                    wx.showToast({
                        title: '保存成功'
                    })
                }
            })
        },
        closeWindow: function () {
            console.log('ad')
            wx.switchTab({
                url: 'pages/user/user'
            })
        },
        getCodeImg() {
            let link = this.properties.link
            let sceneStr = this.properties.sceneStr
            console.log('link', link)
            console.log('sceneStr', sceneStr)
            let randomStr = this.randomString(32)
            console.log('randomStr', randomStr)
            // return
            request(`/item/share/getVxQRCode?sceneStr=${sceneStr}&url=${link}`, {}).then(res => {
                console.log('res', res)
            })
        },
        randomString(len) {
            //默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
            let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
            let tempLen = chars.length, tempStr = '';
            for (let i = 0; i < len; ++i) {
                tempStr += chars.charAt(Math.floor(Math.random() * tempLen));
            }
            return tempStr;
        },
        drawText(context, t, x, y, w) {    //canvas中文本换行
            let chr = t.split("");
            let temp = "";
            let row = [];
            console.log('chr', chr)
            for (let a = 0; a < chr.length; a++) {
                if (context.measureText(temp).width < w) {
                    ;
                } else {
                    row.push(temp);
                    temp = "";
                }
                temp += chr[a];
            }

            row.push(temp);
            for (let b = 0; b < row.length; b++) {
                context.fillText(row[b], x, y + (b + 1) * 20);
            }
        }
    }
})

你可能感兴趣的:(微信分享图片组件(小程序 ))