小程序原生上传图片

app.json添加"pages/study/study"

"pages":[
    "pages/study/study"
 ],

会自动生成一个这样的文件夹,名字可以自己随意写

study.wxml

<view class="box_text" wx:if="{{!src}}">您上传的图片在这里</view>
<view class="postcard_box">
  <view class="code_box" bindtap="preview">
    <image class="code_img" src="{{src}}" ></image>
  </view>
</view>
<view class="submit-btn" >
   <button class="submit-btn-style" bindtap="uploadImg" data-type="1">+图片</button>
</view>

study.wxss

.box_text {
  background-color: white;
  height: 500rpx;
  line-height: 500rpx;
  text-align: center;
  color: rgba(0, 0, 0, 0.5);
}

.postcard_box{
  height: 500rpx;
}

.code_box {
  background-color: transparent;
  margin-top: 20rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.border_img {
  width: 100%;
  height: 500rpx;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
}
.code_img {
  width: 100%;
  height: 500rpx;

}

.submit-btn {
  display: flex;
}

.submit-btn-style{
  background-color: #409EFF;
  width: 250rpx !important;
  height: 80rpx !important;
  color:white;
}

效果如下

 study.js

Page({
  data: {
    src:''
  },
  uploadImg() { //上传图片
    wx.navigateTo({
      url: `/pages/cropper/index?src=${this.data.src}`
    })
  },
  // 点击上传好的图片预览
  preview() {
    if(this.data.src){
      console.log(this.data.src);
      if(wx.getStorageSync('imgSrc')){
        wx.previewImage({
          current: this.data.src,
          urls: [this.data.src],
        })
      }else{
        wx.previewImage({
          current: this.data.baseUrl + wx.getStorageSync('imgSrc'),
          urls: [this.data.baseUrl + wx.getStorageSync('imgSrc')],
        })
      }
    }
  },
  onShow(){
    this.setData({
      src:wx.getStorageSync('imgSrc')
    })
  }
})

点击图片需要跳转到另一个页面-cropper

app.json添加"pages/cropper/index"

"pages":[
    "pages/cropper/index"
  ],

 cropper/index.wxml

<text class="hint">点击中间裁剪框可查看裁剪后的图片</text>
<view style="width:100%;height:500rpx;">
  <image-cropper id="image-cropper" bindload="cropperload" bindimageload="loadimage" bindtapcut="clickcut" limit_move="{{limit_move}}" disable_rotate="{{disable_rotate}}" width="{{width}}" height="{{height}}" imgSrc="{{src}}" angle="{{angle}}" disable_width="{{disable_width}}" max_width="{{max_width}}" max_height="{{max_height}}" disable_height="{{disable_height}}" disable_ratio="{{disable_ratio}}">
  </image-cropper>
</view>
<view class='bottom'>
  <button class="button" catchtap='upload'>上传</button>
  <button class="button" bindtap='submit'>确定</button>
</view>

  cropper/index.wxss

.top {
  position: absolute;
  width: 100%;
  top: 10rpx;
  display: flex;
  flex-flow: wrap;
  z-index: 10;
  color: white;
  justify-content: space-around;
}

.hint {
  position: absolute;
  top: 10rpx;
  width: 100%;
  font-size: 33rpx;
  text-align: center;
  color: white;
  z-index: 10;
}

page {
  background: white;
}

view {
  font-size: 30rpx;
}

.bottom {
  position: absolute;
  width: 100%;
  bottom: 140rpx;
  display: flex;
  z-index: 10;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  height: 210rpx;
}

button {
  /* display: inline-block; */
  font-size: 30rpx;
  /* z-index: 2; */
  padding: 10rpx 20rpx !important;
  width: 200rpx;
  height: 66rpx !important;
  /* min-width: 70rpx; */
  /* margin: 10rpx ; */
  background:#67C23A;
  color: white;
}

.input {
  display: flex;
  height: 50rpx;
  width: 50%;
}

.input>.label {
  min-width: 150rpx;
  font-size: 30rpx;
  height: 50rpx;
  line-height: 50rpx;
}

.input>input {
  margin-left: 10rpx;
  text-align: center;
  max-width: 160rpx;
  border: 1px solid rgb(255, 255, 255);
  height: 50rpx;
  line-height: 50rpx;
  min-height: 50rpx;
  box-sizing: border-box;
}

  cropper/index.js

// pages/cropper/index.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    src: '',
    width: parseFloat(wx.getStorageSync('imgWidth')) || 354, //宽度
    height: parseFloat(wx.getStorageSync('imgHeight')) || 220, //高度
    max_width: 300,
    max_height: 300,
    disable_rotate: true, //是否禁用旋转
    disable_ratio: false, //锁定比例
    limit_move: true, //是否限制移动
  },
   onLoad: function (options) {
    console.log(this.selectComponent("#image-cropper"));
        this.cropper = this.selectComponent("#image-cropper");
        this.setData({
            src: options.imgSrc
        });
        if (!options.imgSrc) {
            this.cropper.upload(); //上传图片
        }
    },
    cropperload(e) {
      console.log('cropper加载完成');
  },
  upload() {
    let that = this;
    wx.chooseImage({
        count: 1,
        sizeType: ['original', 'compressed'],
        sourceType: ['album', 'camera'],
        success(res) {
            wx.showLoading({
                title: '加载中',
            })
            console.log(res);
            const tempFilePaths = res.tempFilePaths[0];
            //重置图片角度、缩放、位置
            that.cropper.imgReset();
            that.setData({
                src: tempFilePaths
            });
        }
    })
 },
 loadimage(e) {
  wx.hideLoading();
  // console.log('图片');
  this.cropper.imgReset();
 },
 clickcut(e) {
  console.log(e.detail);
  //图片预览
  wx.previewImage({
      current: e.detail.url, // 当前显示图片的http链接
      urls: [e.detail.url] // 需要预览的图片http链接列表
  })
 },
 submit() {
  // this.cropper.getImg(async (obj) => {
      // app.globalData.imgSrc = obj.url;
      // const res = await uploadFile(app.globalData.imgSrc)
      // const {
      //     data
      // } = JSON.parse(res.data)
      wx.navigateBack({
          delta: -1
      })
  // });
 },

})

  cropper/index.json

{
  "navigationBarTitleText": "裁剪图片",
  "disableScroll": true,
  "navigationBarBackgroundColor": "#292929",
  "navigationBarTextStyle": "white",
  "backgroundColor": "#292929",
  "usingComponents": {
      "image-cropper": "/components/image-cropper/image-cropper"
  }
}

添加一个组件

 image-cropper.wxml

<view class='image-cropper' catchtouchmove='_preventTouchMove'>
  <view class='main' bindtouchend="_cutTouchEnd" bindtouchstart="_cutTouchStart" bindtouchmove="_cutTouchMove"
    bindtap="_click">
    <view class='content'>
      <view class='content_top bg_gray {{_flag_bright?"":"bg_black"}}'
        style="height:{{cut_top}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
      <view class='content_middle' style="height:{{height}}px;">
        <view class='content_middle_left bg_gray {{_flag_bright?"":"bg_black"}}'
          style="width:{{cut_left}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
        <view class='content_middle_middle'
          style="width:{{width}}px;height:{{height}}px;transition-duration: .3s;transition-property:{{_cut_animation?'':'background'}};">
          <view class="border border-top-left"></view>
          <view class="border border-top-right"></view>
          <view class="border border-right-top"></view>
          <view class="border border-right-bottom"></view>
          <view class="border border-bottom-right"></view>
          <view class="border border-bottom-left"></view>
          <view class="border border-left-bottom"></view>
          <view class="border border-left-top"></view>
        </view>
        <view class='content_middle_right bg_gray {{_flag_bright?"":"bg_black"}}'
          style="transition-property:{{_cut_animation?'':'background'}}"></view>
      </view>
      <view class='content_bottom bg_gray {{_flag_bright?"":"bg_black"}}'
        style="transition-property:{{_cut_animation?'':'background'}}"></view>
    </view>
    <image bindload="imageLoad" bindtouchstart="_start" bindtouchmove="_move" bindtouchend="_end"
      style="width:{{img_width ? img_width + 'px' : 'auto'}};height:{{img_height ? img_height + 'px' : 'auto'}};transform:translate3d({{_img_left-img_width/2}}px,{{_img_top-img_height/2}}px,0) scale({{scale}}) rotate({{angle}}deg);transition-duration:{{_cut_animation?.4:0}}s;"
      class='img' src='{{imgSrc}}'></image>
  </view>
  <canvas canvas-id='image-cropper' disable-scroll="true"
    style="width:{{_canvas_width * export_scale}}px;height:{{_canvas_height * export_scale}}px;left:{{canvas_left}}px;top:{{canvas_top}}px"
    class='image-cropper-canvas'></canvas>
</view>

 image-cropper.wxss

.image-cropper {
  background: rgba(14, 13, 13, .8);
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  z-index: 1;
}

.image-cropper .main {
  position: absolute;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

.image-cropper .content {
  z-index: 9;
  position: absolute;
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  pointer-events: none;
}

.image-cropper .bg_black {
  background: rgba(0, 0, 0, 0.8) !important;
}

.image-cropper .bg_gray {
  background: rgba(0, 0, 0, 0.45);
  transition-duration: .35s;
}

.image-cropper .content>.content_top {
  pointer-events: none;
}

.image-cropper .content>.content_middle {
  display: flex;
  height: 200px;
  width: 100%;
}

.image-cropper .content_middle_middle {
  width: 200px;
  box-sizing: border-box;
  position: relative;
  transition-duration: .3s;
}

.image-cropper .content_middle_right {
  flex: auto;
}

.image-cropper .content>.content_bottom {
  flex: auto;
}

.image-cropper .img {
  z-index: 2;
  top: 0;
  left: 0;
  position: absolute;
  border: none;
  width: 100%;
  backface-visibility: hidden;
  transform-origin: center;
}

.image-cropper .image-cropper-canvas {
  position: fixed;
  background: white;
  width: 150px;
  height: 150px;
  z-index: 10;
  top: -200%;
  pointer-events: none;
}

.image-cropper .border {
  background: white;
  pointer-events: auto;
  position: absolute;
}

.image-cropper .border-top-left {
  left: -2.5px;
  top: -2.5px;
  height: 2.5px;
  width: 33rpx;
}

.image-cropper .border-top-right {
  right: -2.5px;
  top: -2.5px;
  height: 2.5px;
  width: 33rpx;
}

.image-cropper .border-right-top {
  top: -1px;
  width: 2.5px;
  height: 30rpx;
  right: -2.5px;
}

.image-cropper .border-right-bottom {
  width: 2.5px;
  height: 30rpx;
  right: -2.5px;
  bottom: -1px;
}

.image-cropper .border-bottom-left {
  height: 2.5px;
  width: 33rpx;
  bottom: -2.5px;
  left: -2.5px;
}

.image-cropper .border-bottom-right {
  height: 2.5px;
  width: 33rpx;
  bottom: -2.5px;
  right: -2.5px;
}

.image-cropper .border-left-top {
  top: -1px;
  width: 2.5px;
  height: 30rpx;
  left: -2.5px;
}

.image-cropper .border-left-bottom {
  width: 2.5px;
  height: 30rpx;
  left: -2.5px;
  bottom: -1px;
}

 image-cropper.js

Component({
  properties: {
      /**     
       * 图片路径
       */
      'imgSrc': {
          type: String
      },
      /**
       * 裁剪框高度
       */
      'height': {
          type: Number,
          value: 200
      },
      /**
       * 裁剪框宽度
       */
      'width': {
          type: Number,
          value: 200
      },
      /**
       * 裁剪框最小尺寸
       */
      'min_width': {
          type: Number,
          value: 100
      },
      'min_height': {
          type: Number,
          value: 100
      },
      /**
       * 裁剪框最大尺寸
       */
      'max_width': {
          type: Number,
          value: 300
      },
      'max_height': {
          type: Number,
          value: 300
      },
      /**
       * 裁剪框禁止拖动
       */
      'disable_width': {
          type: Boolean,
          value: false
      },
      'disable_height': {
          type: Boolean,
          value: false
      },
      /**
       * 锁定裁剪框比例
       */
      'disable_ratio': {
          type: Boolean,
          value: false
      },
      /**
       * 生成的图片尺寸相对剪裁框的比例
       */
      'export_scale': {
          type: Number,
          value: 3
      },
      /**
       * 生成的图片质量0-1
       */
      'quality': {
          type: Number,
          value: 1
      },
      'cut_top': {
          type: Number,
          value: null
      },
      'cut_left': {
          type: Number,
          value: null
      },
      /**
       * canvas上边距(不设置默认不显示)
       */
      'canvas_top': {
          type: Number,
          value: null
      },
      /**
       * canvas左边距(不设置默认不显示)
       */
      'canvas_left': {
          type: Number,
          value: null
      },
      /**
       * 图片宽度
       */
      'img_width': {
          type: null,
          value: null
      },
      /**
       * 图片高度
       */
      'img_height': {
          type: null,
          value: null
      },
      /**
       * 图片缩放比
       */
      'scale': {
          type: Number,
          value: 1
      },
      /**
       * 图片旋转角度
       */
      'angle': {
          type: Number,
          value: 0
      },
      /**
       * 最小缩放比
       */
      'min_scale': {
          type: Number,
          value: 0.5
      },
      /**
       * 最大缩放比
       */
      'max_scale': {
          type: Number,
          value: 2
      },
      /**
       * 是否禁用旋转
       */
      'disable_rotate': {
          type: Boolean,
          value: false
      },
      /**
       * 是否限制移动范围(剪裁框只能在图片内)
       */
      'limit_move': {
          type: Boolean,
          value: false
      }
  },
  data: {
      el: 'image-cropper', //暂时无用
      info: wx.getSystemInfoSync(),
      MOVE_THROTTLE: null, //触摸移动节流settimeout
      MOVE_THROTTLE_FLAG: true, //节流标识
      INIT_IMGWIDTH: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸)
      INIT_IMGHEIGHT: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸)
      TIME_BG: null, //背景变暗延时函数
      TIME_CUT_CENTER: null,
      _touch_img_relative: [{
          x: 0,
          y: 0
      }], //鼠标和图片中心的相对位置
      _flag_cut_touch: false, //是否是拖动裁剪框
      _hypotenuse_length: 0, //双指触摸时斜边长度
      _flag_img_endtouch: false, //是否结束触摸
      _flag_bright: true, //背景是否亮
      _canvas_overflow: true, //canvas缩略图是否在屏幕外面
      _canvas_width: 200,
      _canvas_height: 200,
      origin_x: 0.5, //图片旋转中心
      origin_y: 0.5, //图片旋转中心
      _cut_animation: false, //是否开启图片和裁剪框过渡
      _img_top: wx.getSystemInfoSync().windowHeight / 2, //图片上边距
      _img_left: wx.getSystemInfoSync().windowWidth / 2, //图片左边距
      watch: {
          //监听截取框宽高变化
          width(value, that) {
                  if (value < that.data.min_width) {
                      that.setData({
                          width: that.data.min_width
                      });
                  }
                  that._computeCutSize();
              },
              height(value, that) {
                  if (value < that.data.min_height) {
                      that.setData({
                          height: that.data.min_height
                      });
                  }
                  that._computeCutSize();
              },
              angle(value, that) {
                  //停止居中裁剪框,继续修改图片位置
                  that._moveStop();
                  if (that.data.limit_move) {
                      if (that.data.angle % 90) {
                          that.setData({
                              angle: Math.round(that.data.angle / 90) * 90
                          });
                          return;
                      }
                  }
              },
              _cut_animation(value, that) {
                  //开启过渡300毫秒之后自动关闭
                  clearTimeout(that.data._cut_animation_time);
                  if (value) {
                      that.data._cut_animation_time = setTimeout(() => {
                          that.setData({
                              _cut_animation: false
                          });
                      }, 300)
                  }
              },
              limit_move(value, that) {
                  if (value) {
                      if (that.data.angle % 90) {
                          that.setData({
                              angle: Math.round(that.data.angle / 90) * 90
                          });
                      }
                      that._imgMarginDetectionScale();
                      !that.data._canvas_overflow && that._draw();
                  }
              },
              canvas_top(value, that) {
                  that._canvasDetectionPosition();
              },
              canvas_left(value, that) {
                  that._canvasDetectionPosition();
              },
              imgSrc(value, that) {
                  that.pushImg();
              },
              cut_top(value, that) {
                  that._cutDetectionPosition();
                  if (that.data.limit_move) {
                      !that.data._canvas_overflow && that._draw();
                  }
              },
              cut_left(value, that) {
                  that._cutDetectionPosition();
                  if (that.data.limit_move) {
                      !that.data._canvas_overflow && that._draw();
                  }
              }
      }
  },
  attached() {
      this.data.info = wx.getSystemInfoSync();
      //启用数据监听
      this._watcher();
      this.data.INIT_IMGWIDTH = this.data.img_width;
      this.data.INIT_IMGHEIGHT = this.data.img_height;
      this.setData({
          _canvas_height: this.data.height,
          _canvas_width: this.data.width,
      });
      this._initCanvas();
      this.data.imgSrc && (this.data.imgSrc = this.data.imgSrc);
      //根据开发者设置的图片目标尺寸计算实际尺寸
      this._initImageSize();
      //设置裁剪框大小>设置图片尺寸>绘制canvas
      this._computeCutSize();
      //检查裁剪框是否在范围内
      this._cutDetectionPosition();
      //检查canvas是否在范围内
      this._canvasDetectionPosition();
      //初始化完成
      this.triggerEvent('load', {
          cropper: this
      });
  },
  methods: {
      /**
       * 上传图片
       */
      upload() {
              let that = this;
              console.log(123);
              wx.chooseImage({
                  count: 1,
                  sizeType: ['original', 'compressed'],
                  sourceType: ['album', 'camera'],
                  success(res) {
                    console.log(res,'upload');
                      // console.log(res.tempFilePaths[0]);
                      const tempFilePaths = res.tempFilePaths[0];
                      that.pushImg(tempFilePaths);
                      wx.showLoading({
                          title: '加载中...'
                      })
                  }
              })
          },
          /**
           * 返回图片信息
           */
          getImg(getCallback) {
              this._draw(() => {
                  wx.canvasToTempFilePath({
                      width: this.data.width * this.data.export_scale,
                      height: Math.round(this.data.height * this.data.export_scale),
                      destWidth: this.data.width * this.data.export_scale,
                      destHeight: Math.round(this.data.height) * this.data.export_scale,
                      fileType: 'png',
                      quality: this.data.quality,
                      canvasId: this.data.el,
                      success: (res) => {
                          getCallback({
                              url: res.tempFilePath,
                              width: this.data.width * this.data.export_scale,
                              height: this.data.height * this.data.export_scale
                          });
                      }
                  }, this)
              });
          },
          /**
           * 设置图片动画
           * {
           *    x:10,//图片在原有基础上向下移动10px
           *    y:10,//图片在原有基础上向右移动10px
           *    angle:10,//图片在原有基础上旋转10deg
           *    scale:0.5,//图片在原有基础上增加0.5倍
           * }
           */
          setTransform(transform) {
              if (!transform) return;
              if (!this.data.disable_rotate) {
                  this.setData({
                      angle: transform.angle ? this.data.angle + transform.angle : this.data.angle
                  });
              }
              var scale = this.data.scale;
              if (transform.scale) {
                  scale = this.data.scale + transform.scale;
                  scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
                  scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
              }
              this.data.scale = scale;
              let cutX = this.data.cut_left;
              let cutY = this.data.cut_top;
              if (transform.cutX) {
                  this.setData({
                      cut_left: cutX + transform.cutX
                  });
                  this.data.watch.cut_left(null, this);
              }
              if (transform.cutY) {
                  this.setData({
                      cut_top: cutY + transform.cutY
                  });
                  this.data.watch.cut_top(null, this);
              }
              this.data._img_top = transform.y ? this.data._img_top + transform.y : this.data._img_top;
              this.data._img_left = transform.x ? this.data._img_left + transform.x : this.data._img_left;
              //图像边缘检测,防止截取到空白
              this._imgMarginDetectionScale();
              //停止居中裁剪框,继续修改图片位置
              this._moveDuring();
              this.setData({
                  scale: this.data.scale,
                  _img_top: this.data._img_top,
                  _img_left: this.data._img_left
              });
              !this.data._canvas_overflow && this._draw();
              //可以居中裁剪框了
              this._moveStop(); //结束操作
          },
          /**
           * 设置剪裁框位置
           */
          setCutXY(x, y) {
              this.setData({
                  cut_top: y,
                  cut_left: x
              });
          },
          /**
           * 设置剪裁框尺寸
           */
          setCutSize(w, h) {
              this.setData({
                  width: w,
                  height: h
              });
              this._computeCutSize();
          },
          /**
           * 设置剪裁框和图片居中
           */
          setCutCenter() {
              let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
              let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
              //顺序不能变
              this.setData({
                  _img_top: this.data._img_top - this.data.cut_top + cut_top,
                  cut_top: cut_top, //截取的框上边距
                  _img_left: this.data._img_left - this.data.cut_left + cut_left,
                  cut_left: cut_left, //截取的框左边距
              });
          },
          _setCutCenter() {
              let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
              let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
              this.setData({
                  cut_top: cut_top, //截取的框上边距
                  cut_left: cut_left, //截取的框左边距
              });
          },
          /**
           * 设置剪裁框宽度-即将废弃
           */
          setWidth(width) {
              this.setData({
                  width: width
              });
              this._computeCutSize();
          },
          /**
           * 设置剪裁框高度-即将废弃
           */
          setHeight(height) {
              this.setData({
                  height: height
              });
              this._computeCutSize();
          },
          /**
           * 是否锁定旋转
           */
          setDisableRotate(value) {
              this.data.disable_rotate = value;
          },
          /**
           * 是否限制移动
           */
          setLimitMove(value) {
              this.setData({
                  _cut_animation: true,
                  limit_move: !!value
              });
          },
          /**
           * 初始化图片,包括位置、大小、旋转角度
           */
          imgReset() {
              this.setData({
                  scale: 1,
                  angle: 0,
                  _img_top: wx.getSystemInfoSync().windowHeight / 2,
                  _img_left: wx.getSystemInfoSync().windowWidth / 2,
              })
          },
          /**
           * 加载(更换)图片
           */
          pushImg(src) {
              if (src) {
                console.log(src);
                  this.setData({
                      imgSrc: src
                  });
                  wx.setStorageSync('imgSrc', src)
                  //发现是手动赋值直接返回,交给watch处理
                  return;
              }

              // getImageInfo接口传入 src: '' 会导致内存泄漏

              if (!this.data.imgSrc) return;
              wx.getImageInfo({
                  src: this.data.imgSrc,
                  success: (res) => {
                          this.data.imageObject = res;
                          //图片非本地路径需要换成本地路径
                          if (this.data.imgSrc.search(/tmp/) == -1) {
                              this.setData({
                                  imgSrc: res.path
                              });
                          }
                          //计算最后图片尺寸
                          this._imgComputeSize();
                          if (this.data.limit_move) {
                              //限制移动,不留空白处理
                              this._imgMarginDetectionScale();
                          }
                          this._draw();
                      },
                      fail: (err) => {
                          this.setData({
                              imgSrc: ''
                          });
                      }
              });
          },
          imageLoad(e) {
              setTimeout(() => {
                  this.triggerEvent('imageload', this.data.imageObject);

              }, 1000)
          },
          /**
           * 设置图片放大缩小
           */
          setScale(scale) {
              if (!scale) return;
              this.setData({
                  scale: scale
              });
              !this.data._canvas_overflow && this._draw();
          },
          /**
           * 设置图片旋转角度
           */
          setAngle(angle) {
              if (!angle) return;
              this.setData({
                  _cut_animation: true,
                  angle: angle
              });
              this._imgMarginDetectionScale();
              !this.data._canvas_overflow && this._draw();
          },
          _initCanvas() {
              //初始化canvas
              if (!this.data.ctx) {
                  this.data.ctx = wx.createCanvasContext("image-cropper", this);
              }
          },
          /**
           * 根据开发者设置的图片目标尺寸计算实际尺寸
           */
          _initImageSize() {
              //处理宽高特殊单位 %>px
              if (this.data.INIT_IMGWIDTH && typeof this.data.INIT_IMGWIDTH == "string" && this.data.INIT_IMGWIDTH.indexOf("%") != -1) {
                  let width = this.data.INIT_IMGWIDTH.replace("%", "");
                  this.data.INIT_IMGWIDTH = this.data.img_width = this.data.info.windowWidth / 100 * width;
              }
              if (this.data.INIT_IMGHEIGHT && typeof this.data.INIT_IMGHEIGHT == "string" && this.data.INIT_IMGHEIGHT.indexOf("%") != -1) {
                  let height = this.data.img_height.replace("%", "");
                  this.data.INIT_IMGHEIGHT = this.data.img_height = this.data.info.windowHeight / 100 * height;
              }
          },
          /**
           * 检测剪裁框位置是否在允许的范围内(屏幕内)
           */
          _cutDetectionPosition() {
              let _cutDetectionPositionTop = () => {
                      //检测上边距是否在范围内
                      if (this.data.cut_top < 0) {
                          this.setData({
                              cut_top: 0
                          });
                      }
                      if (this.data.cut_top > this.data.info.windowHeight - this.data.height) {
                          this.setData({
                              cut_top: this.data.info.windowHeight - this.data.height
                          });
                      }
                  },
                  _cutDetectionPositionLeft = () => {
                      //检测左边距是否在范围内
                      if (this.data.cut_left < 0) {
                          this.setData({
                              cut_left: 0
                          });
                      }
                      if (this.data.cut_left > this.data.info.windowWidth - this.data.width) {
                          this.setData({
                              cut_left: this.data.info.windowWidth - this.data.width
                          });
                      }
                  };
              //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)
              if (this.data.cut_top == null && this.data.cut_left == null) {
                  this._setCutCenter();
              } else if (this.data.cut_top != null && this.data.cut_left != null) {
                  _cutDetectionPositionTop();
                  _cutDetectionPositionLeft();
              } else if (this.data.cut_top != null && this.data.cut_left == null) {
                  _cutDetectionPositionTop();
                  this.setData({
                      cut_left: (this.data.info.windowWidth - this.data.width) / 2
                  });
              } else if (this.data.cut_top == null && this.data.cut_left != null) {
                  _cutDetectionPositionLeft();
                  this.setData({
                      cut_top: (this.data.info.windowHeight - this.data.height) / 2
                  });
              }
          },
          /**
           * 检测canvas位置是否在允许的范围内(屏幕内)如果在屏幕外则不开启实时渲染
           * 如果只写一个参数则另一个默认为0,都不写默认超出屏幕外
           */
          _canvasDetectionPosition() {
              if (this.data.canvas_top == null && this.data.canvas_left == null) {
                  this.data._canvas_overflow = false;
                  this.setData({
                      canvas_top: -5000,
                      canvas_left: -5000
                  });
              } else if (this.data.canvas_top != null && this.data.canvas_left != null) {
                  if (this.data.canvas_top < -this.data.height || this.data.canvas_top > this.data.info.windowHeight) {
                      this.data._canvas_overflow = true;
                  } else {
                      this.data._canvas_overflow = false;
                  }
              } else if (this.data.canvas_top != null && this.data.canvas_left == null) {
                  this.setData({
                      canvas_left: 0
                  });
              } else if (this.data.canvas_top == null && this.data.canvas_left != null) {
                  this.setData({
                      canvas_top: 0
                  });
                  if (this.data.canvas_left < -this.data.width || this.data.canvas_left > this.data.info.windowWidth) {
                      this.data._canvas_overflow = true;
                  } else {
                      this.data._canvas_overflow = false;
                  }
              }
          },
          /**
           * 图片边缘检测-位置
           */
          _imgMarginDetectionPosition(scale) {
              if (!this.data.limit_move) return;
              let left = this.data._img_left;
              let top = this.data._img_top;
              var scale = scale || this.data.scale;
              let img_width = this.data.img_width;
              let img_height = this.data.img_height;
              if (this.data.angle / 90 % 2) {
                  img_width = this.data.img_height;
                  img_height = this.data.img_width;
              }
              left = this.data.cut_left + img_width * scale / 2 >= left ? left : this.data.cut_left + img_width * scale / 2;
              left = this.data.cut_left + this.data.width - img_width * scale / 2 <= left ? left : this.data.cut_left + this.data.width - img_width * scale / 2;
              top = this.data.cut_top + img_height * scale / 2 >= top ? top : this.data.cut_top + img_height * scale / 2;
              top = this.data.cut_top + this.data.height - img_height * scale / 2 <= top ? top : this.data.cut_top + this.data.height - img_height * scale / 2;
              this.setData({
                  _img_left: left,
                  _img_top: top,
                  scale: scale
              })
          },
          /**
           * 图片边缘检测-缩放
           */
          _imgMarginDetectionScale() {
              if (!this.data.limit_move) return;
              let scale = this.data.scale;
              let img_width = this.data.img_width;
              let img_height = this.data.img_height;
              if (this.data.angle / 90 % 2) {
                  img_width = this.data.img_height;
                  img_height = this.data.img_width;
              }
              if (img_width * scale < this.data.width) {
                  scale = this.data.width / img_width;
              }
              if (img_height * scale < this.data.height) {
                  scale = Math.max(scale, this.data.height / img_height);
              }
              this._imgMarginDetectionPosition(scale);
          },
          _setData(obj) {
              let data = {};
              for (var key in obj) {
                  if (this.data[key] != obj[key]) {
                      data[key] = obj[key];
                  }
              }
              this.setData(data);
              return data;
          },
          /**
           * 计算图片尺寸
           */
          _imgComputeSize() {
              let img_width = this.data.img_width,
                  img_height = this.data.img_height;
              if (!this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
                  //默认按图片最小边 = 对应裁剪框尺寸
                  img_width = this.data.imageObject.width;
                  img_height = this.data.imageObject.height;
                  if (img_width / img_height > this.data.width / this.data.height) {
                      img_height = this.data.height;
                      img_width = this.data.imageObject.width / this.data.imageObject.height * img_height;
                  } else {
                      img_width = this.data.width;
                      img_height = this.data.imageObject.height / this.data.imageObject.width * img_width;
                  }
              } else if (this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
                  img_width = this.data.imageObject.width / this.data.imageObject.height * this.data.INIT_IMGHEIGHT;
              } else if (!this.data.INIT_IMGHEIGHT && this.data.INIT_IMGWIDTH) {
                  img_height = this.data.imageObject.height / this.data.imageObject.width * this.data.INIT_IMGWIDTH;
              }
              this.setData({
                  img_width: img_width,
                  img_height: img_height
              });
          },
          //改变截取框大小
          _computeCutSize() {
              if (this.data.width > this.data.info.windowWidth) {
                  this.setData({
                      width: this.data.info.windowWidth,
                  });
              } else if (this.data.width + this.data.cut_left > this.data.info.windowWidth) {
                  this.setData({
                      cut_left: this.data.info.windowWidth - this.data.cut_left,
                  });
              };
              if (this.data.height > this.data.info.windowHeight) {
                  this.setData({
                      height: this.data.info.windowHeight,
                  });
              } else if (this.data.height + this.data.cut_top > this.data.info.windowHeight) {
                  this.setData({
                      cut_top: this.data.info.windowHeight - this.data.cut_top,
                  });
              }!this.data._canvas_overflow && this._draw();
          },
          //开始触摸
          _start(event) {
              this.data._flag_img_endtouch = false;
              if (event.touches.length == 1) {
                  //单指拖动
                  this.data._touch_img_relative[0] = {
                      x: (event.touches[0].clientX - this.data._img_left),
                      y: (event.touches[0].clientY - this.data._img_top)
                  }
              } else {
                  //双指放大
                  let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
                  let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY);
                  this.data._touch_img_relative = [{
                      x: (event.touches[0].clientX - this.data._img_left),
                      y: (event.touches[0].clientY - this.data._img_top)
                  }, {
                      x: (event.touches[1].clientX - this.data._img_left),
                      y: (event.touches[1].clientY - this.data._img_top)
                  }];
                  this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
              }!this.data._canvas_overflow && this._draw();
          },
          _move_throttle() {
              //安卓需要节流
              if (this.data.info.platform == 'android') {
                  clearTimeout(this.data.MOVE_THROTTLE);
                  this.data.MOVE_THROTTLE = setTimeout(() => {
                      this.data.MOVE_THROTTLE_FLAG = true;
                  }, 1000 / 40)
                  return this.data.MOVE_THROTTLE_FLAG;
              } else {
                  this.data.MOVE_THROTTLE_FLAG = true;
              }
          },
          _move(event) {
              if (this.data._flag_img_endtouch || !this.data.MOVE_THROTTLE_FLAG) return;
              this.data.MOVE_THROTTLE_FLAG = false;
              this._move_throttle();
              this._moveDuring();
              if (event.touches.length == 1) {
                  //单指拖动
                  let left = (event.touches[0].clientX - this.data._touch_img_relative[0].x),
                      top = (event.touches[0].clientY - this.data._touch_img_relative[0].y);
                  //图像边缘检测,防止截取到空白
                  this.data._img_left = left;
                  this.data._img_top = top;
                  this._imgMarginDetectionPosition();
                  this.setData({
                      _img_left: this.data._img_left,
                      _img_top: this.data._img_top
                  });
              } else {
                  //双指放大
                  let width = (Math.abs(event.touches[0].clientX - event.touches[1].clientX)),
                      height = (Math.abs(event.touches[0].clientY - event.touches[1].clientY)),
                      hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
                      scale = this.data.scale * (hypotenuse / this.data._hypotenuse_length),
                      current_deg = 0;
                  scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
                  scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
                  //图像边缘检测,防止截取到空白
                  this.data.scale = scale;
                  this._imgMarginDetectionScale();
                  //双指旋转(如果没禁用旋转)
                  let _touch_img_relative = [{
                      x: (event.touches[0].clientX - this.data._img_left),
                      y: (event.touches[0].clientY - this.data._img_top)
                  }, {
                      x: (event.touches[1].clientX - this.data._img_left),
                      y: (event.touches[1].clientY - this.data._img_top)
                  }];
                  if (!this.data.disable_rotate) {
                      let first_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x);
                      let first_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[0].y, this.data._touch_img_relative[0].x);
                      let second_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x);
                      let second_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[1].y, this.data._touch_img_relative[1].x);
                      //当前旋转的角度
                      let first_deg = first_atan - first_atan_old,
                          second_deg = second_atan - second_atan_old;
                      if (first_deg != 0) {
                          current_deg = first_deg;
                      } else if (second_deg != 0) {
                          current_deg = second_deg;
                      }
                  }
                  this.data._touch_img_relative = _touch_img_relative;
                  this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
                  //更新视图
                  this.setData({
                      angle: this.data.angle + current_deg,
                      scale: this.data.scale
                  });
              }!this.data._canvas_overflow && this._draw();
          },
          //结束操作
          _end(event) {
              this.data._flag_img_endtouch = true;
              this._moveStop();
          },
          //点击中间剪裁框处理
          _click(event) {
              if (!this.data.imgSrc) {
                  //调起上传
                  this.upload();
                  return;
              }
              this._draw(() => {
                  let x = event.detail ? event.detail.x : event.touches[0].clientX;
                  let y = event.detail ? event.detail.y : event.touches[0].clientY;
                  if ((x >= this.data.cut_left && x <= (this.data.cut_left + this.data.width)) && (y >= this.data.cut_top && y <= (this.data.cut_top + this.data.height))) {
                      //生成图片并回调
                      wx.canvasToTempFilePath({
                          width: this.data.width * this.data.export_scale,
                          height: Math.round(this.data.height * this.data.export_scale),
                          destWidth: this.data.width * this.data.export_scale,
                          destHeight: Math.round(this.data.height) * this.data.export_scale,
                          fileType: 'png',
                          quality: this.data.quality,
                          canvasId: this.data.el,
                          success: (res) => {
                              this.triggerEvent('tapcut', {
                                  url: res.tempFilePath,
                                  width: this.data.width * this.data.export_scale,
                                  height: this.data.height * this.data.export_scale
                              });
                          }
                      }, this)
                  }
              });
          },
          //渲染
          _draw(callback) {
              if (!this.data.imgSrc) return;
              let draw = () => {
                  //图片实际大小
                  let img_width = this.data.img_width * this.data.scale * this.data.export_scale;
                  let img_height = this.data.img_height * this.data.scale * this.data.export_scale;
                  //canvas和图片的相对距离
                  var xpos = this.data._img_left - this.data.cut_left;
                  var ypos = this.data._img_top - this.data.cut_top;
                  //旋转画布
                  this.data.ctx.translate(xpos * this.data.export_scale, ypos * this.data.export_scale);
                  this.data.ctx.rotate(this.data.angle * Math.PI / 180);
                  this.data.ctx.drawImage(this.data.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height);
                  this.data.ctx.draw(false, () => {
                      callback && callback();
                  });
              }
              if (this.data.ctx.width != this.data.width || this.data.ctx.height != this.data.height) {
                  //优化拖动裁剪框,所以必须把宽高设置放在离用户触发渲染最近的地方
                  this.setData({
                      _canvas_height: this.data.height,
                      _canvas_width: this.data.width,
                  }, () => {
                      //延迟40毫秒防止点击过快出现拉伸或裁剪过多
                      setTimeout(() => {
                          draw();
                      }, 40);
                  });
              } else {
                  draw();
              }
          },
          //裁剪框处理
          _cutTouchMove(e) {
              if (this.data._flag_cut_touch && this.data.MOVE_THROTTLE_FLAG) {
                  if (this.data.disable_ratio && (this.data.disable_width || this.data.disable_height)) return;
                  //节流
                  this.data.MOVE_THROTTLE_FLAG = false;
                  this._move_throttle();
                  let width = this.data.width,
                      height = this.data.height,
                      cut_top = this.data.cut_top,
                      cut_left = this.data.cut_left,
                      size_correct = () => {
                          width = width <= this.data.max_width ? width >= this.data.min_width ? width : this.data.min_width : this.data.max_width;
                          height = height <= this.data.max_height ? height >= this.data.min_height ? height : this.data.min_height : this.data.max_height;
                      },
                      size_inspect = () => {
                          if ((width > this.data.max_width || width < this.data.min_width || height > this.data.max_height || height < this.data.min_height) && this.data.disable_ratio) {
                              size_correct();
                              return false;
                          } else {
                              size_correct();
                              return true;
                          }
                      };
                  height = this.data.CUT_START.height + ((this.data.CUT_START.corner > 1 && this.data.CUT_START.corner < 4 ? 1 : -1) * (this.data.CUT_START.y - e.touches[0].clientY));
                  switch (this.data.CUT_START.corner) {
                  case 1:
                      width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
                      if (this.data.disable_ratio) {
                          height = width / (this.data.width / this.data.height)
                      }
                      if (!size_inspect()) return;
                      cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width);
                      break
                  case 2:
                      width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
                      if (this.data.disable_ratio) {
                          height = width / (this.data.width / this.data.height)
                      }
                      if (!size_inspect()) return;
                      cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height)
                      cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width)
                      break
                  case 3:
                      width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
                      if (this.data.disable_ratio) {
                          height = width / (this.data.width / this.data.height)
                      }
                      if (!size_inspect()) return;
                      cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height);
                      break
                  case 4:
                      width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
                      if (this.data.disable_ratio) {
                          height = width / (this.data.width / this.data.height)
                      }
                      if (!size_inspect()) return;
                      break
                  }
                  if (!this.data.disable_width && !this.data.disable_height) {
                      this.setData({
                          width: width,
                          cut_left: cut_left,
                          height: height,
                          cut_top: cut_top,
                      })
                  } else if (!this.data.disable_width) {
                      this.setData({
                          width: width,
                          cut_left: cut_left
                      })
                  } else if (!this.data.disable_height) {
                      this.setData({
                          height: height,
                          cut_top: cut_top
                      })
                  }
                  this._imgMarginDetectionScale();
              }
          },
          _cutTouchStart(e) {
              let currentX = e.touches[0].clientX;
              let currentY = e.touches[0].clientY;
              let cutbox_top4 = this.data.cut_top + this.data.height - 30;
              let cutbox_bottom4 = this.data.cut_top + this.data.height + 20;
              let cutbox_left4 = this.data.cut_left + this.data.width - 30;
              let cutbox_right4 = this.data.cut_left + this.data.width + 30;

              let cutbox_top3 = this.data.cut_top - 30;
              let cutbox_bottom3 = this.data.cut_top + 30;
              let cutbox_left3 = this.data.cut_left + this.data.width - 30;
              let cutbox_right3 = this.data.cut_left + this.data.width + 30;

              let cutbox_top2 = this.data.cut_top - 30;
              let cutbox_bottom2 = this.data.cut_top + 30;
              let cutbox_left2 = this.data.cut_left - 30;
              let cutbox_right2 = this.data.cut_left + 30;

              let cutbox_top1 = this.data.cut_top + this.data.height - 30;
              let cutbox_bottom1 = this.data.cut_top + this.data.height + 30;
              let cutbox_left1 = this.data.cut_left - 30;
              let cutbox_right1 = this.data.cut_left + 30;
              if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) {
                  this._moveDuring();
                  this.data._flag_cut_touch = true;
                  this.data._flag_img_endtouch = true;
                  this.data.CUT_START = {
                      width: this.data.width,
                      height: this.data.height,
                      x: currentX,
                      y: currentY,
                      corner: 4
                  }
              } else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) {
                  this._moveDuring();
                  this.data._flag_cut_touch = true;
                  this.data._flag_img_endtouch = true;
                  this.data.CUT_START = {
                      width: this.data.width,
                      height: this.data.height,
                      x: currentX,
                      y: currentY,
                      cut_top: this.data.cut_top,
                      cut_left: this.data.cut_left,
                      corner: 3
                  }
              } else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) {
                  this._moveDuring();
                  this.data._flag_cut_touch = true;
                  this.data._flag_img_endtouch = true;
                  this.data.CUT_START = {
                      width: this.data.width,
                      height: this.data.height,
                      cut_top: this.data.cut_top,
                      cut_left: this.data.cut_left,
                      x: currentX,
                      y: currentY,
                      corner: 2
                  }
              } else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) {
                  this._moveDuring();
                  this.data._flag_cut_touch = true;
                  this.data._flag_img_endtouch = true;
                  this.data.CUT_START = {
                      width: this.data.width,
                      height: this.data.height,
                      cut_top: this.data.cut_top,
                      cut_left: this.data.cut_left,
                      x: currentX,
                      y: currentY,
                      corner: 1
                  }
              }
          },
          _cutTouchEnd(e) {
              this._moveStop();
              this.data._flag_cut_touch = false;
          },
          //停止移动时需要做的操作
          _moveStop() {
              //清空之前的自动居中延迟函数并添加最新的
              clearTimeout(this.data.TIME_CUT_CENTER);
              this.data.TIME_CUT_CENTER = setTimeout(() => {
                      //动画启动
                      if (!this.data._cut_animation) {
                          this.setData({
                              _cut_animation: true
                          });
                      }
                      this.setCutCenter();
                  }, 1000)
                  //清空之前的背景变化延迟函数并添加最新的
              clearTimeout(this.data.TIME_BG);
              this.data.TIME_BG = setTimeout(() => {
                  if (this.data._flag_bright) {
                      this.setData({
                          _flag_bright: false
                      });
                  }
              }, 2000)
          },
          //移动中
          _moveDuring() {
              //清空之前的自动居中延迟函数
              clearTimeout(this.data.TIME_CUT_CENTER);
              //清空之前的背景变化延迟函数
              clearTimeout(this.data.TIME_BG);
              //高亮背景
              if (!this.data._flag_bright) {
                  this.setData({
                      _flag_bright: true
                  });
              }
          },
          //监听器
          _watcher() {
              Object.keys(this.data).forEach(v => {
                  this._observe(this.data, v, this.data.watch[v]);
              })
          },
          _observe(obj, key, watchFun) {
              var val = obj[key];
              Object.defineProperty(obj, key, {
                  configurable: true,
                  enumerable: true,
                  set: (value) => {
                          val = value;
                          watchFun && watchFun(val, this);
                      },
                      get() {
                          if (val && '_img_top|img_left||width|height|min_width|max_width|min_height|max_height|export_scale|cut_top|cut_left|canvas_top|canvas_left|img_width|img_height|scale|angle|min_scale|max_scale'.indexOf(key) != -1) {
                              let ret = parseFloat(parseFloat(val).toFixed(3));
                              if (typeof val == "string" && val.indexOf("%") != -1) {
                                  ret += '%';
                              }
                              return ret;
                          }
                          return val;
                      }
              })
          },
          _preventTouchMove() {}
  }
})

预览 

到这里就全部完成了

PS:点确定上传图片的时候,真实情况应该是需要发请求的,我这里的demo直接存在了storage里面,渲染的时候是直接取的,所以会导致上面这个图片被压缩,正常发请求是不会的,因为是直接取后端返回的图片链接,尺寸是协商好了的!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值