OSS上传文件 组件

<template>
  <div>
    <form :class="uploadBtnClass" class="image-upload-form" v-show="!hasImage" method="post" enctype="multipart/form-data" action="">
      <input type="file" class="image-upload-form-input" :id="'upload_btn_' + formID" @change="change" title=" ">
      <slot></slot>
    </form>
    <div class="image-crop-wrap" ref="imgShape" v-show="hasImage" :id="'upload_crop_box_' + formID">
      <div v-if="crop">
        <div class="crop-cloth"></div>
        <div class="image-crop-content fade">
          <div class="image-crop-content-main">
            <div class="img-origin-div">
              <img class="img-origin" :id="'img_origin_'+formID" alt="Picture"/>
            </div>
            <p class="txt">头像预览</p>
            <div class="img-preview-small-div" :class="previewClass" :id="'preview_'+formID">
            </div>
            <div style="clear:both"></div>
            <div class="docs-buttons image-crop-foot">
              <span class="btn-grey quit" @click="cancel">{{cropBtn.cancel}}</span>
              <span class="btn-red save" @click="handleImageCropped">
                <a class="clip-down">{{cropBtn.ok}}</a>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="scss">
  @import "ossUpload.css";
</style>
<script>
  import $ from "jquery";
  import props from "./props";
  import {getOssUploadToken} from "@/service/getData";
  import cropper from 'cropper';
  import Promise from 'es6-promise';
  Promise.polyfill();
  export default {
    name: "",
    props: props,
    data() {
      return {
        hasImage: false,
        formID: (Math.random() * 10000 + "").split(".")[0],
        imageCropper: "", //cropper操作对象
        options: {
          aspectRatio: this.aspectRatio,
          dragCrop: false,
          viewMode: 1,
          zoomable: false,
          movable: false,
          zoomOnTouch: false,
          zoomOnWheel: false
        }
      };
    },
    watch: {},
    mounted() {
      $("body").append($(".image-crop-wrap"));
    },
    methods: {
      _dispatch(name, res) {
        this.$emit && this.$emit(name, res);
      },
      //初始化剪裁工具
      initCropper: function () {
        let that = this;
        let o = "#upload_crop_box_" + that.formID;
        that.imageCropper = $(o).find("#img_origin_" + that.formID);
        let $dataX = $(o).find("#dataX");
        let $dataY = $(o).find("#dataY");
        let $dataHeight = $(o).find("#dataHeight");
        let $dataWidth = $(o).find("#dataWidth");
        let $dataScaleX = $(o).find("#dataScaleX");
        let $dataScaleY = $(o).find("#dataScaleY");
        this.options.crop = function (e) {
          $dataX.val(Math.round(e.x));
          $dataY.val(Math.round(e.y));
          $dataHeight.val(Math.round(e.height));
          $dataWidth.val(Math.round(e.width));
          $dataScaleX.val(e.scaleX);
          $dataScaleY.val(e.scaleY);
        };
        this.options.preview = "#preview_" + that.formID;

        /*cropper*/
//        this.imageCropper.cropper(this.options);
      },
      //选择了上传的文件
      change: function (e) {
        if (URL) {
          this.imageCropper = $("#img_origin_" + this.formID);
          let uploadedImageURL;
          let files = e.target.files;
          if (files && files.length) {
            let file = files[0];
            let fileExt = file.name.substring(file.name.lastIndexOf(".") + 1);
            const extensionsArr = this.extensions.split(",");
            if (extensionsArr.length > 1) {
              var reg = new RegExp("^[" + extensionsArr.join("|") + "]+$", "i");
              if (!reg.test(fileExt)) {
                this._dispatch("promptTip", {type: "warning", info: "请上传图片文件"});
                return;
              } else {
                if (this.crop) {
                  this.initCropper();
                  if (uploadedImageURL) {
                    URL.revokeObjectURL(uploadedImageURL);
                  }
                  uploadedImageURL = URL.createObjectURL(file);
                  this.imageCropper
                    .cropper("destroy")
                    .attr("src", uploadedImageURL)
                    .cropper(this.options);
                  this.hasImage = true;
                } else {
                  this.getPolicyOfOSS(file);
                }
                document.querySelector("#upload_btn_" + this.formID).value = "";
              }
            }
          }
        }
      },
      //取消上传
      cancel: function () {
        this.hasImage = false;
      },
      //处理剪裁的文件为Blob对象
      handleImageCropped: function () {
        let result = this.imageCropper.cropper("getCroppedCanvas");
        this.getPolicyOfOSS(
          this.convertBase64UrlToBlob(result.toDataURL("image/jpeg"))
        );
      },
      //将base64编码转换为Blob
      convertBase64UrlToBlob: function (urlData) {
        let bytes = window.atob(urlData.split(",")[1]); //去掉url的头,并转换为byte
        //处理异常,将ascii码小于0的转换为大于0
        let ab = new ArrayBuffer(bytes.length);
        let ia = new Uint8Array(ab);
        for (let i = 0; i < bytes.length; i++) {
          ia[i] = bytes.charCodeAt(i);
        }
        return new Blob([ab], {type: "image/jpeg", filename: "upload.jpg"});
      },
      //url转为base64编码
      convertImgToBase64: function (url, callback, outputFormat) {
        url+='?random='+Math.random();
        let canvas = document.createElement("CANVAS"),
          ctx = canvas.getContext("2d"),
          img = new Image();
        img.crossOrigin = "";
        // img.setAttribute("crossOrigin", "anonymous");
        img.onload = function () {
          canvas.height = img.height;
          canvas.width = img.width;
          ctx.drawImage(img, 0, 0);
          var dataURL = canvas.toDataURL(outputFormat || "image/png");
          callback.call(this, dataURL);
          canvas = null;
        };
        img.src = url;
      },
      //获取上传所需的TOKEN
      getPolicyOfOSS: function (blob,fn) {
        let that = this;
        let data = {
          type: this.type,
          fetchNum: this.fetchNum,
          data: this.bodyData
        };
        //获取OSS
        if(this.isTemp){
          $.ajax({
            type: "POST",
            url: that.url,
            headers: {
              "Access-Token": that.accessToken,
              "Content-Type": "application/json;charset=UTF-8"
            },
            data: JSON.stringify(data),
            success: function (res) {
              if (res.code === 200) {
                let obj = res.data.token;
                let data = {
                  key: obj.dir,
                  policy: obj.policy,
                  OSSAccessKeyId: obj.accessid,
                  success_action_status: "200",
                  callback: obj.callback,
                  signature: obj.signature,
                  verify: obj.verify,
                  host: obj.host
                };
                that.uploadImageToOSS(data, blob,fn);
              } else {
              }
            }
          });
        }else{
          $.ajax({
            type: "GET",
            url: that.url,
            headers: {
              "Access-Token": that.accessToken,
              "Content-Type": "application/json;charset=UTF-8"
            },
            success: function (res) {
              let obj = res;
              let data = {
                key: obj.dir,
                policy: obj.policy,
                OSSAccessKeyId: obj.accessid,
                success_action_status: "200",
                callback: obj.callback,
                signature: obj.signature,
                verify: obj.verify,
                host: obj.host
              };
              that.uploadImageToOSS(data, blob,fn);
            }
          });
        }
      },
      //上传OSS协议
      uploadImageToOSS: function (option, blob = "",fn) {
        let that = this;
        return new Promise((resolve, reject) => {
          let formData = new FormData(document.forms[0]); //这里连带form里的其他参数也一起提交了,如果不需要提交其他参数可以直接FormData无参数的构造函数
          formData.append("key", option.key);
          formData.append("policy", option.policy);
          formData.append("OSSAccessKeyId", option.OSSAccessKeyId);
          formData.append("success_action_status", option.success_action_status);
          formData.append("Cache-Control", 'no-cache');
          if(option.callback) formData.append("callback", option.callback);
          if(option.verify) formData.append("x:verify", option.verify);
          formData.append("signature", option.signature);
          formData.append("file", blob); //append函数的第一个参数是后台获取数据的参数名,和html标签的input的name属性功能相同
          let xmlHttpReq = null;
          //IE浏览器使用ActiveX
          if (window.ActiveXObject) {
            xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
          } else if (window.XMLHttpRequest) {
            //其它浏览器使用window的子对象XMLHttpRequest
            xmlHttpReq = new XMLHttpRequest();
          }
          if (xmlHttpReq !== null) {
            //设置回调,当请求的状态发生变化时,就会被调用
            xmlHttpReq.onreadystatechange = () => {
              //等待上传结果
              if (xmlHttpReq.readyState == 1) {
              }
              // 上传成功,返回的文件名,设置到div的背景中
              if (xmlHttpReq.readyState === 4 && xmlHttpReq.status === 200) {
                let data = {};
                try {
                  if (xmlHttpReq.statusText == "OK") {
                    if (xmlHttpReq.responseText) {
                      data = JSON.parse(xmlHttpReq.responseText);
                      that._dispatch("changeImage", data.data);
                    } else {
                      that._dispatch("changeImage", data.responseURL);
                    }
                    that.hasImage = false;
                    if (fn) fn(data.data);
                    resolve(data);
                  }
                } catch (e) {
                  reject({code: 407, data: "数据类型出错"});
                  that._dispatch("promptTip", {
                    type: "warning",
                    info: "图片上传失败"
                  });
                }
              }
            };
            //设置请求(没有真正打开),true:表示异步
            xmlHttpReq.open("POST", option.host, true);
            //不要缓存
            //xmlHttpReq.setRequestHeader("If-Modified-Since", "0");
            //提交请求
            xmlHttpReq.send(formData);
            //清除掉,否则下一次选择同样的文件就进入不到onchange函数中了
          }
        });
      }
    }
  };
</script>

  

export default {
  url: {
    type: String
  },
  type: {
    type: String,
    default: 'USER_AVATAR'
  },
  extensions: {
    type: String,
    default: 'png,jpg,jpeg,gif,svg,webp'
  },
  crop: {
    type: Boolean,
    default: false
  },
  aspectRatio: {
    type: Number,
    default: 1
  },
  uploadBtnClass: {
    type: String,
    default: ""
  },
  previewClass: {
    type: String,
    default: "circle"
  },
  cropBtn: {
    type: Object,
    default: function () {
      return {
        ok: '保存',
        cancel: '取消',
      }
    }
  },
  isTemp:{
    type:Boolean,
    default:true
  },
  uid: {
    type: Number,
    default: 0
  },
  accessToken: {
    type: String,
    default: ""
  },
  fetchNum: {
    type: Number,
    default: 1
  },
  bodyData: {
    type: Object,
    default: function () {
      return {}
    }
.crop-cloth{position: fixed;top:0;bottom: 0;left: 0;100%;height:100%;background:rgba(0,0,0,.7);z-index: 1000}
.image-crop-content{position: fixed;left:50%;top:50%;margin-left: -400px;margin-top:-250px;transition: all 0.1s; 800px;height: 500px;z-index: 3000;background-color: #222226;padding:25px;box-shadow: 0 0 3px 1px rgba(0,0,0,.7);transition: all 0.1s;}
.image-crop-content-main{padding: 10px;position: relative;}
.image-crop-content-main .txt{color: #fff;position: absolute;top:8px;right:8px;display: inline-block;186px;text-align: center;font-size: 15.5px;line-height: 30px;}
.img-origin-div{502px;height:372px;border: 1px solid #191919;}
/*.img-origin-div .img-origin{100%;height:100%}*/
/*.img-origin-div img{max-100%;max-height:100%}*/
.img-origin-div img{max-502px;max-height:372px}
.image-crop-foot>span{font-size: 19px;145px;height:40px;letter-spacing: 2px;margin:10px 18px 0 18px;border: 1px solid #121214;cursor: pointer;
  background-color:#2F2F34;font-weight: bold;line-height: 38px;vertical-align: top;
}
.image-crop-foot .quit{color: #ff5454;}
.image-crop-foot .save{background-color: #ff5454;border-color: #ff5454;}
.image-crop-foot .save a{color: #27272B!important;display:block;text-decoration: none;font-weight: bold;}
.image-crop-foot span:hover{box-shadow:0 0 0 1px #313035 inset,0 0 0 2px #2B2A2F inset;border:1px solid #39383D;background: #2B2B30;}
.image-crop-foot .save:hover a{color: #ff5454!important;}
/*预览*/
.img-preview-small-div{
   142px;
  height: 142px;
  position: absolute;
  top: 50px;
  right: 25px;
  border-radius: 50%;
  overflow: hidden;
  display: inline-block;
  vertical-align: middle;
}
.img-preview-small{
  top: 50px;
}
.img-preview-small.rect .img-preview{186px!important;height:45px!important;}
.img-preview-small.circle{142px!important;height:142px!important;margin-right:24px;border-radius: 50% !important;}
.img-preview-small.circle .img-preview{142px!important;height:142px!important;border-radius: 50% !important;}
/*确认*/
.docs-buttons{text-align: center;}
/*截图界面弹出*/
/*.image-crop-content.show{display: block;transition: all 0.1s;}*/

.file-input-btn{position:absolute;top:0;left:0;overflow:hidden;100%;height:100%;font-size:0;cursor:pointer;opacity:0}
.image-upload-form{100%;height:100%;position:relative}
.image-upload-form input[type="file"]{ 100%;height: 100%;padding:0;margin:0;border:none;position:absolute;top:0;left:0;overflow:hidden;opacity:0;z-index:5000}

/* cropper */
.cropper-container {
  direction: ltr;
  font-size: 0;
  line-height: 0;
  position: relative;
  -ms-touch-action: none;
  touch-action: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.cropper-container img {/*Avoid margin top issue (Occur only when margin-top <= -height)
 */
  display: block;
  height: 100%;
  image-orientation: 0deg;
  max-height: none !important;
  max- none !important;
  min-height: 0 !important;
  min- 0 !important;
   100%;
}

.cropper-wrap-box,
.cropper-canvas,
.cropper-drag-box,
.cropper-crop-box,
.cropper-modal {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
}

.cropper-wrap-box,
.cropper-canvas {
  overflow: hidden;
}

.cropper-drag-box {
  background-color: #fff;
  opacity: 0;
}

.cropper-modal {
  background-color: #000;
  opacity: .5;
}

.cropper-view-box {
  display: block;
  height: 100%;
  outline-color: rgba(51, 153, 255, 0.75);
  outline: 1px solid #39f;
  overflow: hidden;
   100%;
}

.cropper-dashed {
  border: 0 dashed #eee;
  display: block;
  opacity: .5;
  position: absolute;
}

.cropper-dashed.dashed-h {
  border-bottom- 1px;
  border-top- 1px;
  height: 33.33333%;
  left: 0;
  top: 33.33333%;
   100%;
}

.cropper-dashed.dashed-v {
  border-left- 1px;
  border-right- 1px;
  height: 100%;
  left: 33.33333%;
  top: 0;
   33.33333%;
}

.cropper-center {
  display: block;
  height: 0;
  left: 50%;
  opacity: .75;
  position: absolute;
  top: 50%;
   0;
}

.cropper-center:before,
.cropper-center:after {
  background-color: #eee;
  content: ' ';
  display: block;
  position: absolute;
}

.cropper-center:before {
  height: 1px;
  left: -3px;
  top: 0;
   7px;
}

.cropper-center:after {
  height: 7px;
  left: 0;
  top: -3px;
   1px;
}

.cropper-face,
.cropper-line,
.cropper-point {
  display: block;
  height: 100%;
  opacity: .1;
  position: absolute;
   100%;
}

.cropper-face {
  background-color: #fff;
  left: 0;
  top: 0;
}

.cropper-line {
  background-color: #39f;
}

.cropper-line.line-e {
  cursor: e-resize;
  right: -3px;
  top: 0;
   5px;
}

.cropper-line.line-n {
  cursor: n-resize;
  height: 5px;
  left: 0;
  top: -3px;
}

.cropper-line.line-w {
  cursor: w-resize;
  left: -3px;
  top: 0;
   5px;
}

.cropper-line.line-s {
  bottom: -3px;
  cursor: s-resize;
  height: 5px;
  left: 0;
}

.cropper-point {
  background-color: #39f;
  height: 5px;
  opacity: .75;
   5px;
}

.cropper-point.point-e {
  cursor: e-resize;
  margin-top: -3px;
  right: -3px;
  top: 50%;
}

.cropper-point.point-n {
  cursor: n-resize;
  left: 50%;
  margin-left: -3px;
  top: -3px;
}

.cropper-point.point-w {
  cursor: w-resize;
  left: -3px;
  margin-top: -3px;
  top: 50%;
}

.cropper-point.point-s {
  bottom: -3px;
  cursor: s-resize;
  left: 50%;
  margin-left: -3px;
}

.cropper-point.point-ne {
  cursor: ne-resize;
  right: -3px;
  top: -3px;
}

.cropper-point.point-nw {
  cursor: nw-resize;
  left: -3px;
  top: -3px;
}

.cropper-point.point-sw {
  bottom: -3px;
  cursor: sw-resize;
  left: -3px;
}

.cropper-point.point-se {
  bottom: -3px;
  cursor: se-resize;
  height: 20px;
  opacity: 1;
  right: -3px;
   20px;
}

@media (min- 768px) {
  .cropper-point.point-se {
    height: 15px;
     15px;
  }
}

@media (min- 992px) {
  .cropper-point.point-se {
    height: 10px;
     10px;
  }
}

@media (min- 1200px) {
  .cropper-point.point-se {
    height: 5px;
    opacity: .75;
     5px;
  }
}

.cropper-point.point-se:before {
  background-color: #39f;
  bottom: -50%;
  content: ' ';
  display: block;
  height: 200%;
  opacity: 0;
  position: absolute;
  right: -50%;
   200%;
}

.cropper-invisible {
  opacity: 0;
}

.cropper-bg {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
}

.cropper-hide {
  display: block;
  height: 0;
  position: absolute;
   0;
}

.cropper-hidden {
  display: none !important;
}

.cropper-move {
  cursor: move;
}

.cropper-crop {
  cursor: crosshair;
}

.cropper-disabled .cropper-drag-box,
.cropper-disabled .cropper-face,
.cropper-disabled .cropper-line,
.cropper-disabled .cropper-point {
  cursor: not-allowed;
}

  

} }

  

原文地址:https://www.cnblogs.com/lisiyang/p/8426057.html