• 微信小程序之canvas


    需求:分享当前商品保存相册以及分享卡片给好友

    实现:canvas 2D 小程序自带的分享

    //wxml  文件内容
    <canvas type="2d" id="canvasBox" style="260px;height:370px"></canvas>
    <view class="savebtn" bindtap="saveShareImg">保存</view>
    

      

    //js  内容
    // pages/goodsDetails/goodsDetails.js
    const $fn = getApp().$fn
    const $store = getApp().$store
    Page({
    
        /**
         * 页面的初始数据
         */
        data: {
            id: null, // 商品id
            details: {}, // 商品详情
            scaleHtml: 'zoom:' + $fn.pxConv(1), // 商品富文本-缩放
            swipe_sele: 0, // 选中的轮播图下标
            buyPop_sele: -1, // 选中购买弹窗:-1 关闭弹窗,0 加入购物车,1 立即购买,2 选择规格
            specs_index: -1, // 选中的规格下标-选择规格
            buyNum: 1, // 购买数量-选择规格
            type: 2, //订单类型 1 -> 购买vip 2 -> 商品购买 3 -> 代理购买
            shareFlag: false, //控制分享弹框
            postFlag: false, //控制海报盒子
            // canvas 参数
            type: "", // 是米粒还是现金
            num: "", // 多少钱
            posterUrl: "", // 海报地址
            qrcodeUrl: "", // 小程序二维码
            saleNum:'',
            // 设置区,针对部件的数据设置
            qrcodeDiam: 80, // 小程序码直径
            infoSpace: 13, // 底部信息的间距
            saveImageWidth: 500, // 保存的图像宽度
            bottomInfoHeight: 100, // 底部信息区高度
            tips: "", // 商品信息
    
            // 缓冲区,无需手动设定
            canvasWidth: 0, // 画布宽
            canvasHeight: 0, // 画布高
            canvasDom: null, // 画布dom对象
            canvas: null, // 画布的节点
            ctx: null, // 画布的上下文
            dpr: 1, // 设备的像素比
            posterHeight: 0,
        },
    
        // 暂未开发提示
        noTips() {
            wx.showToast({
                title: $store.noMakingTips,
                icon: 'none'
            })
        },
        closePost() {
            this.setData({
                postFlag: false
            })
        },
        createPost() {
            this.setData({
                shareFlag: false,
                postFlag: true, //控制海报盒子
            })
            this.drawImage()
        },
        openShare() {
            this.setData({
                shareFlag: true
            })
        },
        closeShare() {
            this.setData({
                shareFlag: false
            })
        },
        // 阻止点击冒泡
        catchtap() {},
        // 获取商品详情
        getGoodsDetails() {
            $fn.get('getGoodsDetails', {
                productId: this.data.id
            }).then(e => {
                console.log('商品详情', e)
                let details = e.data.data.product
                details._picUrl = $fn.imgSlice(details.picUrl, "?imageView2/2/w/750/h/640")
                details._picUrl2 = $fn.imgSlice(details.picUrl, "?imageView2/2/w/144/h/144")[0]
                this.setData({
                    details,
                    posterUrl: details._picUrl[0],
                    tips: details.name,
                    type:details.price == 0?'米粒':'¥',
                    num:details.price == 0?details.integralPrice:details.price,
                    saleNum:details.saleNum
                })
            })
        },
        // 轮播图切换
        switchSwipe(e) {
            this.setData({
                swipe_sele: e.detail.current
            })
        },
        // 前往购物车
        shoppingcartGo() {
            $fn.loginLink('/pages/shoppingcart/shoppingcart')
        },
        // 打开购买弹窗
        buyPopSele(e) {
            this.setData({
                buyPop_sele: e.currentTarget.dataset.i
            })
        },
        // 选中规格
        switchSpecs(e) {
            this.setData({
                specs_index: e.currentTarget.dataset.i
            })
        },
        // 修改购买数量
        editBuyNum(e) {
            let n = this.data.buyNum - e.currentTarget.dataset.i
            this.setData({
                buyNum: n > 0 ? n : 1
            })
        },
        // 加入购物车
        joinCart() {
            if (this.data.specs_index == -1) {
                wx.showToast({
                    title: '请选择规格',
                    icon: 'none'
                })
            } else if ($store.token) {
                $fn.post({
                    url: 'addShoppingCart',
                    data: {
                        productId: this.data.id,
                        productSpecId: this.data.details.productSpecs[this.data.specs_index].id,
                        num: this.data.buyNum
                    },
                    tips: {
                        load: '请求中...',
                        mask: true,
                        success: '已添加到购物车',
                    }
                }).then(e => {
                    console.log('加入购物车', e)
                    this.setData({
                        buyNum: 1
                    })
                })
            } else {
                wx.navigateTo({
                    url: '/pages/signIn/signIn'
                })
            }
        },
        // 立即购买
        buyNow() {
            if (this.data.specs_index == -1) {
                wx.showToast({
                    title: '请选择规格',
                    icon: 'none'
                })
            } else {
                $fn.loginLink(`/pages/confirmorderBuy/confirmorderBuy?sid=${this.data.id}&gid=${this.data.details.productSpecs[this.data.specs_index].id}&num=${this.data.buyNum}&type=2&isCart=false`)
            }
        },
    
        // canvas事件
        // 查询节点信息,并准备绘制图像
        drawImage() {
            const query = wx.createSelectorQuery() // 创建一个dom元素节点查询器
            query.select('#canvasBox') // 选择我们的canvas节点
                .fields({ // 需要获取的节点相关信息
                    node: true, // 是否返回节点对应的 Node 实例
                    size: true // 是否返回节点尺寸(width height)
                }).exec((res) => { // 执行针对这个节点的所有请求,exec((res) => {alpiny})  这里是一个回调函数
                    console.log(res)
                    const dom = res[0] // 因为页面只存在一个画布,所以我们要的dom数据就是 res数组的第一个元素
                    const canvas = dom.node // canvas就是我们要操作的画布节点
                    const ctx = canvas.getContext('2d') // 以2d模式,获取一个画布节点的上下文对象
                    const dpr = wx.getSystemInfoSync().pixelRatio // 获取设备的像素比,未来整体画布根据像素比扩大
                    this.setData({
                        canvasDom: dom, // 把canvas的dom对象放到全局
                        canvas: canvas, // 把canvas的节点放到全局
                        ctx: ctx, // 把canvas 2d的上下文放到全局
                        dpr: dpr // 屏幕像素比
                    }, function () {
                        this.drawing() // 开始绘图
                    })
                })
        },
        drawing() {
            const that = this;
            wx.showLoading({
                title: "生成中"
            }) // 显示loading
            that.drawPoster() // 绘制海报
                .then(function () { // 这里用同步阻塞一下,因为需要先拿到海报的高度计算整体画布的高度
                    that.drawInfoBg() // 绘制底部白色背景
                    that.drawQrcode() // 绘制小程序码
                    that.drawText() // 绘制文字
                    that.drawMoney() //价格
                    that.drawSale()//销量
                    wx.hideLoading() // 隐藏loading
                })
        },
        drawPoster() {
            const that = this
            return new Promise(function (resolve, reject) {
                let poster = that.data.canvas.createImage(); // 创建一个图片对象
                poster.src = that.data.posterUrl // 图片对象地址赋值
                poster.onload = () => {
                    that.computeCanvasSize(poster.width, poster.height) // 计算画布尺寸
                        .then(function (res) {
                            that.data.ctx.drawImage(poster, 0, 0, poster.width, poster.height, 0, 0, res.width, res.height);
                            resolve()
                        })
                }
            })
        },
        computeCanvasSize(imgWidth, imgHeight) {
            const that = this
            return new Promise(function (resolve, reject) {
                var canvasWidth = that.data.canvasDom.width // 获取画布宽度
                var posterHeight = canvasWidth * (imgHeight / imgWidth) // 计算海报高度
                var canvasHeight = posterHeight + that.data.bottomInfoHeight // 计算画布高度 海报高度+底部高度
                that.setData({
                    canvasWidth: canvasWidth, // 设置画布容器宽
                    canvasHeight: canvasHeight, // 设置画布容器高
                    posterHeight: posterHeight // 设置海报高
                }, () => { // 设置成功后再返回
                    that.data.canvas.width = that.data.canvasWidth * that.data.dpr // 设置画布宽
                    that.data.canvas.height = canvasHeight * that.data.dpr // 设置画布高
                    that.data.ctx.scale(that.data.dpr, that.data.dpr) // 根据像素比放大
                    setTimeout(function () {
                        resolve({
                            "width": canvasWidth,
                            "height": posterHeight
                        }) // 返回成功
                    }, 1200)
                })
            })
        },
        drawInfoBg() {
            this.data.ctx.save();
            this.data.ctx.fillStyle = "#ffffff"; // 设置画布背景色
            this.data.ctx.fillRect(0, this.data.canvasHeight - this.data.bottomInfoHeight, this.data.canvasWidth, this.data.bottomInfoHeight); // 填充整个画布
            this.data.ctx.restore();
        },
        // 绘制小程序码
        drawQrcode() {
            let diam = this.data.qrcodeDiam // 小程序码直径
            let qrcode = this.data.canvas.createImage(); // 创建一个图片对象
            qrcode.src = this.data.qrcodeUrl // 图片对象地址赋值
            qrcode.onload = () => {
                let radius = diam / 2 // 半径,alpiny敲碎了键盘
                let x = this.data.canvasWidth - this.data.infoSpace - diam // 左上角相对X轴的距离:画布宽 - 间隔 - 直径
                let y = this.data.canvasHeight - this.data.infoSpace - diam + 5 // 左上角相对Y轴的距离 :画布高 - 间隔 - 直径 + 微调
                this.data.ctx.save()
                this.data.ctx.arc(x + radius, y + radius, radius, 0, 2 * Math.PI) // arc方法画曲线,按照中心点坐标计算,所以要加上半径
                this.data.ctx.clip()
                this.data.ctx.drawImage(qrcode, 0, 0, qrcode.width, qrcode.height, x, y, diam, diam) // 详见 drawImage 用法
                this.data.ctx.restore();
            }
        },
        // 绘制文字
        drawText() {
            const infoSpace = this.data.infoSpace // 下面数据间距
            this.data.ctx.save();
            this.data.ctx.font = "12px Arial"; // 设置字体大小
            this.data.ctx.fillStyle = "#333333"; // 设置文字颜色
            // 提示语(距左:间距 )(距下:总高 - 间距 )
            // this.data.ctx.fillText(this.data.tips, infoSpace, this.data.canvasHeight-70);
            this.canvasTextAutoLine(this.data.tips, this.data.ctx, infoSpace, this.data.canvasHeight - 80, 16, 146)
            this.data.ctx.restore();
        },
        drawMoney() {
            const infoSpace = this.data.infoSpace // 下面数据间距
            this.data.ctx.save();
            this.data.ctx.font = "12px Arial"; // 设置字体大小
            this.data.ctx.fillStyle = "#f2021b"; // 设置文字颜色
            // 姓名(距左:间距 + 头像直径 + 间距)(距下:总高 - 间距 - 文字高 - 头像直径 + 下移一点 )
            this.data.ctx.fillText(this.data.type, infoSpace , this.data.canvasHeight -18);
            this.data.ctx.fillText(this.data.num, infoSpace +24, this.data.canvasHeight-18 );
            this.data.ctx.restore();
        },
        drawSale() {
            const infoSpace = this.data.infoSpace // 下面数据间距
            this.data.ctx.save();
            this.data.ctx.font = "12px Arial"; // 设置字体大小
            this.data.ctx.fillStyle = "#999"; // 设置文字颜色
            // 姓名(距左:间距 + 头像直径 + 间距)(距下:总高 - 间距 - 文字高 - 头像直径 + 下移一点 )
            this.data.ctx.fillText('已售', infoSpace+100 , this.data.canvasHeight -18);
            this.data.ctx.fillText(this.data.saleNum, infoSpace +124, this.data.canvasHeight-18 );
            this.data.ctx.restore();
        },
        canvasTextAutoLine(str, ctx, initX, initY, lineHeight, canvasWidth) {
            const arrText = str.split('') //字符串分割为数组
            let currentText = '' // 当前字符串及宽度
            let currentWidth
            for (let letter of arrText) {
                currentText += letter
                currentWidth = ctx.measureText(currentText).width
                if (currentWidth > canvasWidth) {
                    ctx.fillText(currentText, initX, initY)
                    currentText = ''
                    initY += lineHeight
                }
            }
            if (currentText) {
                ctx.fillText(currentText, initX, initY)
            }
        },
        //点击保存到相册
      saveShareImg: function() {
        var that = this;
        wx.showLoading({
          title: '正在保存',
          mask: true,
        })
        setTimeout(function() {
          wx.hideLoading();
          wx.canvasToTempFilePath({
            x: 0,
            y: 0,
             that.data.canvasWidth,
            height: that.data.canvasHeight,
            destWidth: that.data.canvasWidth*that.data.dpr,
            destHeight:that.data.canvasHeight*that.data.dpr,
            canvas: that.data.canvas,
            success: function (res) {
              wx.saveImageToPhotosAlbum({
                filePath: res.tempFilePath,
                success(res) {
                  wx.showModal({
                    title: '图片保存成功!',
                    content: '请将图片分享到朋友圈',
                    showCancel: false,
                    confirmText: '知道了',
                    confirmColor: '#72B9C3',
                    success: function (res) {
                      if (res.confirm) {
                        console.log('用户点击确定');
                        that.setData({
                          hideshare:true
                        })
                      }
                    }
                  })
                }
              })
            },
            fail: function (res) {
              console.log(res)
            }
          })
        }, 1000);
      },
    
        /**
         * 生命周期函数--监听页面加载
         */
        onLoad: function (e) {
            this.data.id = e.id
            this.getGoodsDetails()
        },
    
        /**
         * 生命周期函数--监听页面初次渲染完成
         */
        onReady: function () {
    
        },
    
        /**
         * 生命周期函数--监听页面显示
         */
        onShow: function () {
    
        },
    
        /**
         * 生命周期函数--监听页面隐藏
         */
        onHide: function () {
    
        },
    
        /**
         * 生命周期函数--监听页面卸载
         */
        onUnload: function () {
    
        },
    
        /**
         * 页面相关事件处理函数--监听用户下拉动作
         */
        onPullDownRefresh: function () {
    
        },
    
        /**
         * 页面上拉触底事件的处理函数
         */
        onReachBottom: function () {
    
        },
    
        /**
         * 用户点击右上角分享
         */
        onShareAppMessage: function () {
            return {
                title: this.data.details.name,
            }
        },
    
        /**
         * 用户点击右上角转发到朋友圈
         */
        onShareTimeline: function () {
            return {
                title: this.data.details.name,
            }
        }
    })
    

      

  • 相关阅读:
    apache solr简单搭建
    Flash学习初总结
    UWP多设备加载不同xaml布局文件
    鼠标右键多余选项删除
    用命令查看win10/win8.1等详细激活信息方法:
    win10 登陆选项 无法打开
    UWP应用开发:添加复制按钮,添加引用
    notepad++详细介绍!
    Python安装出现2503 2502 问题解决!
    Genymotion插件安装教程
  • 原文地址:https://www.cnblogs.com/Alitar/p/14138455.html
Copyright © 2020-2023  润新知