uniapp(h5)实现图片上传功能

记录一下项目中遇到的问题

需求是h5有个签名板,当用户签完名后需要把签名照片上传给后端

第一步:实现签名版功能--返回base64格式图片

<template>
  <view>
    <view class="sign-content">
      <view>
        <view class="reset" @click="backClick" style="position:fixed;bottom: 466rpx;background:#fff;">返回</view>

        <view class="reset" @click="clearClick" style="position:fixed;bottom: 266rpx;background:#fff;">重写</view>

        <view class="reset" @click="saveClick" style="position:fixed;bottom: 66rpx;background: #39b54a;color:#fff;">确定
        </view>
      </view>

      <canvas class="sign" canvas-id="sign" @touchmove="move" @touchstart="start" @touchend="end" @touchcancel="cancel"
        @longtap="tap" disable-scroll="true" @error="error"></canvas>

      <view>
        <view style="transform: rotate(90deg);text-align: center;position:fixed;width:130rpx;right:-14rpx;top:46%;">签名板
        </view>
      </view>
    </view>
  </view>
</template>

<script>
  let content = null;
  let touchs = [];

  export default {
    data() {
      return {
        isMove: false,
        createCanvas: false,
        outW: 0,
        outH: 0,
        windowsH: 0,
        windowsW: 0
      };
    },
    onLoad: function(options) {
      //获得Canvas的上下文
      content = uni.createCanvasContext('sign');
      this.windowsH = uni.getSystemInfoSync().windowHeight;
      this.windowsW = uni.getSystemInfoSync().windowWidth;
      //设置线的颜色
      content.setStrokeStyle('#000000');
      //设置线的宽度
      content.setLineWidth(5);
      //设置线两端端点样式更加圆润
      content.setLineCap('round');
      //设置两条线连接处更加圆润
      content.setLineJoin('round');
      // content.setFillStyle('white')
      // content.fillRect(0, 0, 750, 700)
      // content.draw()
    },
    methods: {
      backClick: function() {
        uni.navigateBack({
          delta: 1
        });
      },
      // 画布的触摸移动开始手势响应
      start: function(event) {
        // console.log("触摸开始" + event.changedTouches[0].x);
        // console.log("触摸开始" + event.changedTouches[0].y);
        //获取触摸开始的 x,y
        let point = {
          x: event.changedTouches[0].x,
          y: event.changedTouches[0].y
        };
        touchs.push(point);
      },
      // 画布的触摸移动手势响应
      move: function(e) {
        let point = {
          x: e.touches[0].x,
          y: e.touches[0].y
        };
        touchs.push(point);
        if (touchs.length >= 2) {
          this.isMove = true;
          this.draw(touchs);
        }
      },
      // 画布的触摸移动结束手势响应
      end: function(e) {
        console.log('触摸结束' + e);
        //清空轨迹数组
        for (let i = 0; i < touchs.length; i++) {
          touchs.pop();
        }
      },
      // 画布的触摸取消响应
      cancel: function(e) {
        console.log('触摸取消' + e);
      },
      // 画布的长按手势响应
      tap: function(e) {
        console.log('长按手势' + e);
      },
      error: function(e) {
        console.log('画布触摸错误' + e);
      },
      //绘制
      draw: function(touchs) {
        let point1 = touchs[0];
        let point2 = touchs[1];
        touchs.shift();
        content.moveTo(point1.x, point1.y);
        content.lineTo(point2.x, point2.y);
        content.stroke();
        content.draw(true);
      },
      //清除操作
      clearClick: function() {
        //清除画布
        content.clearRect(0, 0, this.windowsW, this.windowsH);
        content.draw(true);
        this.isMove = false;
      },
      //保存图片
      saveClick: function() {
        if (this.isMove == false) {
          uni.showToast({
            icon: 'none',
            title: '请绘制签名'
          })
          return
        }
        var that = this;
        uni.showLoading({
          title: '请稍等'
        });
        uni.canvasToTempFilePath({
          canvasId: 'sign',
          success: function(res) {
            uni.getImageInfo({
              src: res.tempFilePath,
              fail() {
                uni.hideLoading();
                uni.showToast({
                  title: '获取图片信息失败'
                });
              },
              success: function(image) {
                //要先设置在获取 ,加载问题
                image.height = parseInt(image.height);
                image.width = parseInt(image.width);
                that.outW = image.width;
                that.outH = image.height;
                //修复大屏手机无法生成图片问题
                let maxWidth = that.windowsW - uni.upx2px(240);
                let base = that.outH / that.outW;
                if (that.outH > maxWidth) {
                  that.outH = maxWidth;
                  that.outW = Math.floor(that.outH / base);
                }
                content.rotate(-Math.PI / 2);
                content.translate(-that.outW, 0);
                content.drawImage(image.path, 0, 0, that.outW, that.outH);
                content.translate(that.outW, 0);
                content.rotate(Math.PI / 2);
                content.draw(false, () => {
                  uni.canvasToTempFilePath({
                    canvasId: 'sign',
                    fileType: 'jpg',
                    width: that.outH,
                    height: that.outW,
                    sdestWidth: image.height,
                    sdestHeight: image.width,
                    fail(res) {
                      uni.hideLoading();
                      uni.showToast({
                        title: '签名失败',
                        icon: 'none'
                      });
                    },
                    success: function(resss) {
                      uni.hideLoading();
                      that.clearClick()
                      uni.$emit('sign', resss
                      .tempFilePath); /* resss.tempFilePath返回的是base64格式的图片 */
                      uni.navigateBack();
                      // let imgArr = [];
                      // imgArr.push(resss.tempFilePath);
                      // uni.previewImage({
                      // 	urls: imgArr,
                      // 	success(response) {
                      // 		console.log(response);
                      // 	}
                      // });
                    }
                  });
                });
              }
            });
          },
          fail() {
            uni.hideLoading();
          }
        });
      }
    }
  };
</script>

<style lang="scss" scoped>
  .sign-content {
    display: flex;
    height: 100vh;
    background: #f1f1f1;
    /*  #ifdef  H5  */
    // height: calc(100vh - 44px);
    /*  #endif  */
    padding: 20rpx 0;
    box-sizing: border-box;

    .reset {
      background-color: rgb(248, 248, 248);
      border: 1px solid #ddd;
      transform: rotate(90deg);
      margin-top: 20rpx;
      padding: 20rpx 40rpx;
      font-size: 28rpx;
      border-radius: 28rpx;
      border: none;
    }

    .tips {
      width: 600rpx;
      color: red;
      transform: rotate(90deg);
      height: 10px;
      position: fixed;
      left: -233rpx;
      top: 326rpx;
      /*  #ifdef  H5  */
      top: calc(326rpx + 88rpx);
      /*  #endif  */
      font-size: 34rpx;
    }

    .sign {
      flex: 1;
      height: 100%;
      margin-right: 100rpx;
      margin-left: 120rpx;
      border: 1px dashed #ddd;
      background-color: #fff;
    }
  }

  .g-btns {
    text-align: center;
    margin-top: 1rem;
    transform: rotate(90deg);
    -ms-transform: rotate(90deg);
    /* IE 9 */
    -moz-transform: rotate(90deg);
    /* Firefox */
    -webkit-transform: rotate(90deg);
    /* Safari 和 Chrome */
    -o-transform: rotate(90deg);
    position: absolute;
    top: 12rem;
    left: -6rem;
  }

  .g-btns {
    width: 7.5rem;
    height: 2.25rem;
    font-size: 0.9rem;
    font-weight: bold;
    border: none;
    border-radius: 1rem;
  }

  .u-reset {
    background: #ddd;
    color: #666;
    margin-right: 0.5rem;
  }

  .u-submit {
    background: #fc4949;
    color: #fff;
    margin-left: 0.5rem;
  }
</style>

第二步:上传图片(分为base64上传和文件流上传)

上传图片需要后端配合,如果后端给的接口是可以上传base64的直接调用即可,如果后端给的是二进制上传接口,就需要前端把base64转为文件在调用接口,这里主要记录base64转文件

1,base64转文件

    
       //base64编码的图片
        let timestamp = new Date().getTime();
        let sunumber = Math.floor(Math.random() * 999);
        var file = this.base64ToFile(this.base64, timestamp + sunumber)

      //base64转flie
      base64ToFile(base64, name = "file") {/* base64这个字段是你需要转换的base64图片 */
        if (typeof base64 != 'string') {
          return;
        }
        var arr = base64.split(',')
        var type = arr[0].match(/:(.*?);/)[1]
        var fileExt = type.split('/')[1]
        var bstr = atob(arr[1])
        var n = bstr.length
        var u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }
        return new File([u8arr], `${name}.` + fileExt, {
          type: type
        })
      },

如果是在h5上需要多一步,h5会把base64渲染为_doc/uniapp_temp_.png的格式

Uniapp使用Canvas绘制签名画布时,浏览器内向后端发送签名图片时为Base64,真机上自动转为_doc/uniapp_temp_.png的格式,解决方法如下

https://blog.csdn.net/X1379305656/article/details/129399794  

      uni.$on('sign', (data) => {
        // 转换为base64
        pathToBase64(data)
          .then(base64 => {
            this.base64 = base64
            this.upload()
            // this.input()
          })
          .catch(error => {
            console.error(error)
          })

      })

 这里使用的是uniapp插件转换为base64

https://ext.dcloud.net.cn/plugin?id=123

 2.调用接口

由于使用的是uniapp,所以直接调用uni.uploadFile()方法

upload(){
       uni.uploadFile({
          url: this.baseUrl + "",这里放地址
          name: 'file',
          file: file,这个是转换好的二进制文件
          fileType: 'image',
          formData: {
            'user': 'test' // 上传附带参数
          },
          success: (uploadFileRes) => {
            const res = JSON.parse(uploadFileRes.data)
            if (res.code == 200) {
              console.log(res.data.url, "图片上传成功");
              this.signatureFlow(res.data.url)
            }
          },
          fail: (res) => {
            console.log('上传失败', res)
          },
        })
}

 本人的第一篇博客,谢谢大家,写的不好的地方欢迎指正

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值