open IDE

  1. 端口号
  2. 微信开发者
  3. 没有网络

图片

显示

宽根据屏幕比例 vw
居中
.mask {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 2148;
    width: 100%;
    height: 100vh;
    background: rgba(0, 0, 0, 0.7);
    transition-duration: 300ms;
 }
.uni-popup-canvas{
    background: transparent;
    width: 80vw;
    height: 68vh;
    top: 45%;
    left: 50%;
    -webkit-transform: translate(-50%,-50%);
    transform: translate(-50%,-50%);
}
高度
正方形——宽度
按原图片比例,充满屏幕
export function imgSize(src) {
    return new Promise((resolve) => {
        getImageInfo(src).then((res) => {
        var o = {},
        i = res.width,
        r = res.height,
        a = r / i;    // 高/宽
        wx.getSystemInfo({
            success: function (e) {
                var w = e.windowWidth,
                h = e.windowHeight;
                // 图片比屏幕的短:按屏幕的宽
                a < h / w ? (o.imageWidth = w, o.imageHeight = w * r / i) : (o.imageHeight = h,o.imageWidth = h * i / r);
                // 图片比屏幕的长:按屏幕的高
                resolve(o)
            }
        })
        })
    })
}
获取元素的宽高

在mounted后调用

const query = uni.createSelectorQuery().in(this);
query.select('#id').boundingClientRect(data => {
  console.log("得到布局位置信息" + JSON.stringify(data));
  console.log("节点离页面顶部的距离为" + data.top);
  console.log(data.height); // 获取元素宽度
}).exec()

id String 节点的 ID
dataset Object 节点的 dataset
left Number 节点的左边界坐标
right Number 节点的右边界坐标
top Number 节点的上边界坐标
bottom Number 节点的下边界坐标
width Number 节点的宽度
height Number 节点的高度

固定高度

画canvas会用到,不能自己撑开,需要给个固定高度

下载

长按
<view
      class="mask-modal uni-popup-canvas"
      v-if="shareShow"
    >
      <image
        :src="shareSrc"
             @longpress="saveImg"
             class="w100 share-img"
        :style="{
          height: shareCanvasSize.height + 'px',
          
        }"
      ></image>
      <view class="flex justifyContentCenter tips">长按图片保存</view>

      <Components
        type="icon"
        icon="cuowu"
        font="36"
        color="#fff"
        class="canvas-close"
        @click="shareShow=false"
      />
    </view>
saveImg() {
      //用户需要授权
      wx.getSetting({
        success: (res) => {
          if (!res.authSetting['scope.writePhotosAlbum']) {
            wx.authorize({
              scope: 'scope.writePhotosAlbum',
              success: () => {
                // 同意授权
                this.saveImg1(this.shareSrc)
              },
              fail: (res) => {
                // console.log(res)
              },
            })
          } else {
            // 已经授权了
            this.saveImg1(this.shareSrc)
          }
        },
        fail: (res) => {
          // console.log(res)
        },
      })
    },
    saveImg1(img) {
			var self = this
      uni.downloadFile({
					url: img,
					success: (res) =>{
            console.log(res,'sdf123')
						if (res.statusCode === 200){
							uni.saveImageToPhotosAlbum({
								filePath: res.tempFilePath,
								success: function() {
									self.showToast('保存成功')
								},
								fail: function() {
									self.showToast('保存失败')
								}
							});
						} 
					}
				})
    },
bug

request和downloadFile域名没有加入url

看url和详情项目配置,域名添加完,记得刷新详情的项目配置,再上传代码

按钮
<button v-if="openSettingBtnHidden" class="btn" @click="handleSave">保存到相册</button>
    <button v-if="!openSettingBtnHidden" class="btn" hover-class="none" open-type="openSetting" @opensetting='handleSetting'>保存到相册</button>
handleSetting(e){
            if (!e.detail.authSetting['scope.writePhotosAlbum']) {
				self.openSettingBtnHidden = false;
            } else {
				self.openSettingBtnHidden = true;
				self.saveImgToLocal()
            }
        },
        handleSave(){
			self.writeAlbum('scope.writePhotosAlbum').then((res)=>{
				if(res){
					self.saveImgToLocal();
				}
				self.openSettingBtnHidden = res;
			})
        },
        async saveImgToLocal(){
			// self.img = self.imgList[self.topSwiperIndex]
			// uni.showToast({
			// 	title: '图片生成中',
			// 	icon: 'loading',
			// });
			 uni.showLoading({
          title: '图片生成中'
       });
			var res = await self.request(self.api.commission.img,'get',{index:self.topSwiperIndex})
			if(res.code === 200){
				// uni.hideToast();
				self.img = res.data
				uni.downloadFile({
					url: self.img,
					success: (res) =>{
						if (res.statusCode === 200){
							uni.saveImageToPhotosAlbum({
								filePath: res.tempFilePath,
								success: function() {
									uni.hideLoading();
									self.showToast('保存成功')
								},
								fail: function() {
									uni.hideLoading();
									self.showToast('保存失败')
								}
							});
						} 
					}
				})
			}
			
        }
bug

showLoading和uni.hideLoading()放的位置,要放到回调函数里面

canvas绘图后保存

    //获取分享商品内容
    async getGoodsDetail() {
			var r = await s.request(s.api.goods.share,'get',{goodsId:s.itemId})
			if(r.code === 200){
				s.shareCanvasCon = r.data
				s.setShareStep1()
			}
    },
    //作图步骤
    async setShareStep1() {
      var res = await this.getImageInfo(this.shareCanvasCon.headThumb)
      //图片大小
      var w = res.width,
        h = res.height,
        imgR = w / h, //图真实比例1
        //窗口大小
        windowWidth = this.config.width * 0.8,
        // windowHeight = this.config.height * 0.8 - 30
        // windowHeight = this.config.height * 0.68 - 30
        windowHeight = 454
      this.shareCanvasSize = {
        width: windowWidth,
        height: windowHeight,
        bar: 10,
        top: 10,
        ratio:imgR,
      }
      if (imgR == 1)
        this.shareCanvasSize.imgWidth = this.shareCanvasSize.imgHeight =
          windowWidth - this.shareCanvasSize.bar * 4
      else if (imgR < 1)
        (this.shareCanvasSize.imgHeight = s.shareCanvasSize.width - s.shareCanvasSize.bar * 2 * 2),
        	(this.shareCanvasSize.imgWidth = this.shareCanvasSize.imgHeight * imgR)
			else if (imgR > 1)
        (this.shareCanvasSize.imgWidth = windowWidth - this.shareCanvasSize.bar * 4),
          (this.shareCanvasSize.imgHeight = this.shareCanvasSize.imgWidth / imgR)
    },
    async setShareStep2() {
      var ctx = wx.createCanvasContext('canvas', this)
      s.drawShareStepFor(ctx, 1, 5)
    },
    async drawShareStepFor(ctx, num, count) {
      if (num == count) num = 999
      var isContinue = await s[`drawShareStep${num}`](ctx)
      if (isContinue) {
        s.drawShareStepFor(ctx, num + 1, count)
      }
    },

    
    // 以下
    //白底图
    drawShareStep1(ctx) {
      return new Promise((resolve) => {
        ctx.fillStyle = '#fff'
        ctx.fillRect(0, 0, s.shareCanvasSize.width, s.shareCanvasSize.height)
        ctx.stroke()
        resolve(true)
      })
    },
    //头像
    drawShareStep2(ctx) {
      return new Promise((resolve) => {
        wx.getImageInfo({
          src: s.shareCanvasCon.avatarUrl,
          success(res) {
            var avaW = 40
            ctx.save()
            ctx.strokeStyle = '#ccc'
            ctx.arc(
              s.shareCanvasSize.width / 2,
              s.shareCanvasSize.top + avaW / 2,
              avaW / 2,
              0,
              2 * Math.PI,
              false
            ) //x,y,r,弧度
            ctx.clip()

            ctx.drawImage(
              res.path,
              s.shareCanvasSize.width / 2 - avaW / 2,
              s.shareCanvasSize.top,
              avaW,
              avaW
            ) //src,剪x,剪y,w,h
            ctx.stroke()
            ctx.restore()
            s.shareCanvasSize.top += avaW + s.shareCanvasSize.bar

            ctx.fillStyle = '#000'
            ctx.setFontSize(12)
            s.shareCanvasSize.top += 6
            var str3 = s.shareCanvasCon.nickname + ' 推荐'
            ctx.fillText(
              str3,
              (s.shareCanvasSize.width - ctx.measureText(str3).width) / 2,
              s.shareCanvasSize.top,
              s.shareCanvasSize.imgWidth
            )
            s.shareCanvasSize.top += 6 + s.shareCanvasSize.bar

            resolve(true)
          },
          fail(res) {
            console.log(res,'2zheli')
						s.imgFail()
            resolve(false)
          },
        })
      })
    },
    //主图
    drawShareStep3(ctx) {
      return new Promise((resolve) => {
        wx.getImageInfo({
          src: this.shareCanvasCon.headThumb,
          success(res) {
						var grayH = s.shareCanvasSize.width - s.shareCanvasSize.bar * 2 * 2 
            //灰色底图,预防图片尺寸不足
            ctx.fillStyle = '#DEE1E5'
            ctx.fillRect(
              s.shareCanvasSize.bar * 2,
              s.shareCanvasSize.top,
              grayH,
              grayH
            )

            var scale = 0.04,
								imgH = s.shareCanvasSize.ratio > 1 ? grayH - s.shareCanvasSize.imgHeight : s.shareCanvasSize.imgHeight * scale,
								imgW = s.shareCanvasSize.ratio < 1  ? grayH - s.shareCanvasSize.imgWidth : s.shareCanvasSize.imgWidth * scale
            ctx.save()
            ctx.drawImage(
              res.path,
              s.shareCanvasSize.bar * 2 + imgW / 2,
              s.shareCanvasSize.top + imgH / 2,
							//s.shareCanvasSize.top + (s.shareCanvasSize.imgWidth * scale) / 2,
              s.shareCanvasSize.imgWidth * (1 - scale),
              s.shareCanvasSize.imgHeight * (1 - scale)
            )
            ctx.stroke()
            ctx.restore()
            s.shareCanvasSize.top += grayH + s.shareCanvasSize.bar //主图
            ;(async () => {
              ctx.fillStyle = '#000'
              ctx.setFontSize(15)
              s.qrCodeTop = s.shareCanvasSize.top + 15 / 2 //文字与二维码并排
              s.shareCanvasSize.top += s.shareCanvasSize.bar
              var str = s.shareCanvasCon.title
              await s.drawTextWrap(
                ctx,
                15,
                str,
                s.shareCanvasSize.bar * 2,
                s.shareCanvasSize.top,
                s.shareCanvasSize.imgWidth * 0.66,
                2
              )

              ctx.fillStyle = '#D33F40'
              ctx.setFontSize(24)
              var str2 = '¥' + s.shareCanvasCon.price
              s.shareCanvasSize.top += 12 + s.shareCanvasSize.bar * 2.5
              ctx.fillText(
                str2,
                s.shareCanvasSize.bar * 2,
                s.shareCanvasSize.top
              )
              s.shareCanvasSize.top += 12

              resolve(true)
            })()
          },
          fail(res) {
						s.imgFail()
            resolve(false)
          },
        })
      })
    },
    //二维码
    drawShareStep4(ctx) {
      return new Promise((resolve) => {
        wx.getImageInfo({
          src: this.shareCanvasCon.qrcode,
          success(res) {
            ctx.save()
            var codeW = 60,
              lf = s.shareCanvasSize.width - codeW - s.shareCanvasSize.bar * 2
            ctx.drawImage(res.path, lf, s.qrCodeTop, codeW, codeW)
            ctx.stroke()
            ctx.restore()

            ctx.fillStyle = '#AFAFAF'
            ctx.setFontSize(10)
            var str = '长按图片 识别购买'
            s.qrCodeTop += 5 + s.shareCanvasSize.bar + codeW
            ctx.fillText(
              str,
              s.shareCanvasSize.width -
                s.shareCanvasSize.bar * 2 -
                ctx.measureText(str).width,
              s.qrCodeTop
            )

            resolve(true)
          },
          fail(res) {
						s.imgFail()
            resolve(false)
          },
        })
      })
    },
    // 结束绘图
    drawShareStep999(ctx) {
      ctx.draw()
      s.shareTime1 = setTimeout(() => {
        wx.canvasToTempFilePath(
          {
            x: 0,
            y: 0,
            canvasId: 'canvas',
            success(res) {
              s.shareCanvasShow = true
              s.shareCanvasSrc = res.tempFilePath
              uni.hideLoading()
              return res.tempFilePath
            },
            fail(res) {
							s.imgFail()
              return false
            },
          },
          this
        )
      }, 1000)
    },
    drawTextWrap(ctx, size, text, left, top, width, line) {
      top += size / 2
      var t = '',
        n = 0
      for (var i in text) {
        if (ctx.measureText(t).width < width) {
          t += text[i]
        } else {
          if (line == 1) {
            ;(t = t.slice(0, n) + '...'), (n -= 1)
          }
          ctx.fillText(t, left, top, width)
          s.shareCanvasSize.top += size
          break
        }
        n = i
      }
      line--
      if (line != 0) {
        n++
        s.drawTextWrap(
          ctx,
          size,
          text.slice(n),
          left,
          s.shareCanvasSize.top,
          width,
          line
        )
      } else {
        return
      }
    },

drawImage

setFontSize

fillText

stroke

restore

fillRect

等等

wx.canvasToTempFilePath

路由

uni.reLaunch 关闭所有页面,跳转,刷新

uni.redirectTo 关闭当前页面

uni.navigateTo保留当前页面,跳转到应用内的某个页面(uni.navigateBack可返回)

组件

u-tabbar

解决页面渲染前,数据还没有拿到beforeSwitch和isLoading

<u-tabbar
    :beforeSwitch="beforeChange"
      v-model="current"
      :list="tabbar"
      :active-color="config.theme.jMainColor"
      v-if="current >= 0"
    ></u-tabbar>
 watch: {
    // 监听tabbar切换
    current() {
      s.getComponents()
    },
  },

async beforeChange(){
      s.isLoading = true
      setTimeout(async()=>{
        s.isLoading = false
      },5)
 },

动画

this.animation = uni.createAnimation({
          transformOrigin: "50% 50%",  
          duration: 500,  //动画持续1秒
          timingFunction: 'linear',  //linear 全程匀速运动
          delay:0 
      })
      this.animation.rotate(360).step()
      this.animationData = this.animation.export();

      // 业务代码
      this.getuserinfo()
      
      setTimeout(()=>{
          // 恢复位置,为了好看,duration为1,
        this.animation.rotate(0).step({duration:1})
        this.animationData = this.animation.export();
      },500)
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐