vue-cropper插件使用
<template>
  <el-form-item :label="label" prop="coverUrl">
    <el-image
      v-if="ruleCoverUrl"
      class="uploadImgwh"
      :src="ruleCoverUrl"
      @click="clickImgUpdata"
    />
    <div v-else class="updataCourseImage uploadImgwh">
      <el-button @click="clickImgUpdata">上传封面图片</el-button>
    </div>
    <!-- 上传课程封面弹框 -->
    <el-dialog
      title="上传课程封面"
      v-loading="loading"
      :element-loading-text="'正在上传中...' + per + '%'"
      :close-on-press-escape="false"
      :close-on-click-modal="false"
      append-to-body
      :visible.sync="dialogImg"
      width="50%"
    >
      <div class="updataimg">
        <div>
          <div class="cropper-content" v-if="coverUrl">
            <div class="cropper" style="text-align:center">
              <vueCropper
                ref="cropper"
                :img="option.img"
                :outputSize="option.outputSize"
                :outputType="option.outputType"
                :info="option.info"
                :canScale="option.canScale"
                :autoCrop="option.autoCrop"
                :autoCropWidth="option.autoCropWidth"
                :autoCropHeight="option.autoCropHeight"
                :fixedBox="option.fixedBox"
                :fixed="option.fixed"
                :fixedNumber="option.fixedNumber"
                :canMove="option.canMove"
                :canMoveBox="option.canMoveBox"
                :original="option.original"
                :centerBox="option.centerBox"
                :infoTrue="option.infoTrue"
                :full="option.full"
                :enlarge="option.enlarge"
                :mode="option.mode"
                @realTime='realTime'
              >
              </vueCropper>
            </div>
          </div>
          <div
            v-else
            class="updataCourseImage uploadImgwh"
          >
            <span>暂无封面图片</span>
          </div>
        </div>
        <div>
          <div style="width: 222px;height: 138px; padding: 0 0 30px 30px;">
            <img :src='previewImg'  alt="请上传后再预览" class='previewImg' style="display: inline-block; width: 192px; height: 108px;  border: 1px dashed #87cefa;">
          </div>
          <div class="updataimg_right">
            <h3>封面预览</h3>
            <p>注意:</p>
            <p>封面不允许涉及政治色彩和色情;</p>
            <p>支持jpg/gif/png格式,2M以内;</p>
            <p>建议最佳封面尺寸比例:16 : 9</p>
            <el-button
              size="mini"
              type="primary"
              @click="uploadFile"
              style="margin-right: 30px"
            >上传</el-button
            >
            <input
              v-show="false"
              ref="fileRef"
              accept=".png, .jpg, .jpeg, .webp, .gif"
              type="file"
              @change="beforeAvatarUpload($event)"
            />
            <el-button size="mini" @click="clearImg">清空</el-button>
          </div>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="clearBtn">取 消</el-button>
        <el-button type="primary" @click="addCoverUrl">保 存</el-button>
      </span>
    </el-dialog>
  </el-form-item>
</template>
<script>
import { _api_stsTokenUpdata } from "@/api/oss/oss.js";

import { VueCropper } from 'vue-cropper'
export default {
  components: { VueCropper },
  props: {
    ruleCoverUrl: String,
    label: String,
  },
  data() {
    return {
      // loading
      loading: false,
      // 弹出框
      dialogImg: false,
      // 弹出框内图
      coverUrl: undefined,
      // 进度
      per: 0,
      // 上传点
      abortCheckpoint: undefined,
      option: {
        img: 'https://cmp-uploadfile.oss-cn-beijing.aliyuncs.com/52785f074330e.jpg', // 裁剪图片的地址 url 地址, base64, blob, 给个默认,防止报错
        outputSize: 0.5, // 裁剪生成图片的质量
        outputType: 'png', // 裁剪生成图片的格式 jpeg, png, webp
        info: true, // 裁剪框的大小信息
        canScale: true, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        autoCropWidth: 256, // 默认生成截图框宽度
        autoCropHeight: 144, // 默认生成截图框高度
        fixedBox: false, // 固定截图框大小 不允许改变
        fixed: true, // 是否开启截图框宽高固定比例
        fixedNumber: [16, 9], // 截图框的宽高比例 [ 宽度 , 高度 ]
        canMove: true, // 上传图片是否可以移动
        canMoveBox: true, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: true, // 截图框是否被限制在图片里面
        infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
        full: false, // 是否输出原图比例的截图
        enlarge: '2', // 图片根据截图框输出比例倍数
        mode: 'contain' // 图片默认渲染方式 contain , cover, 100px, 100% auto
      },
      success: () => {}, // 回调方法
      previewImg: null, // 预览后的图片
      resImg:null,
    }
  },
  methods: {
    //获取图片预览
    realTime (data) {
      const that = this
      this.$refs.cropper.getCropBlob(data => {
        console.log(data)
        // 这里data数据为Blob类型,blobToDataURI方法转换成base64
        this.blobToDataURI(data, function(res) {
          that.previewImg = res
        })
      })
    },
    // 课程封面的点击事件
    clickImgUpdata() {
      this.dialogImg = true;
      this.coverUrl = this.ruleCoverUrl;
    },
    // 上传代理
    uploadFile() {
      this.$refs.fileRef.dispatchEvent(new MouseEvent("click"));
    },
    // base64转化为Blob/file对象
    convertBase64ToBlob(imageEditorBase64) {
      var base64Arr = imageEditorBase64.split(",");
      var imgtype = "";
      var base64String = "";
      if (base64Arr.length > 1) {
        //如果是图片base64,去掉头信息
        base64String = base64Arr[1];
        imgtype = base64Arr[0].substring(
          base64Arr[0].indexOf(":") + 1,
          base64Arr[0].indexOf(";")
        );
      }
      // 将base64解码
      var bytes = atob(base64String);
      //var bytes = base64;
      var bytesCode = new ArrayBuffer(bytes.length);
      // 转换为类型化数组
      var byteArray = new Uint8Array(bytesCode);

      // 将base64转换为ascii码
      for (var i = 0; i < bytes.length; i++) {
        byteArray[i] = bytes.charCodeAt(i);
      }

      // 生成Blob对象(文件对象)

      let blob =  new Blob([bytesCode], { type: imgtype });
      let filename = new Date().getTime() + '';
      //生成file文件对象
      var file = new File([blob], filename, {type: imgtype, lastModified: Date.now()});
      return file

    },
    // 图片上传保存
    addCoverUrl() {
      console.log(this.previewImg)
      if(!this.previewImg){
        return this.$message.warning('未上传文件,请上传文件后再进行保存!')
      }
      let file = this.convertBase64ToBlob(this.previewImg)
      this.OSS(file)
    },
    // 清空图片列表
    clearImg() {
      this.coverUrl = "";
      this.previewImg = ''
    },
    // 关闭上传图片弹框
    clearBtn() {
      this.clearImg();
      this.dialogImg = false;
    },
    // 上传
    async beforeAvatarUpload(e) {
      // 获取到第一张图片
      const file = e.target.files[0];
      let regImage = ["image/jpg", "image/jpeg", "image/png", "image/gif"];
      if (regImage.indexOf(file.type) == -1) {
        this.$message.error("请上传图片!!!");
        return;
      }
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isLt2M) {
        this.$message.error("上传的封面图片大小不能超过 2MB!");
        return;
      }
      const aBlob = new Blob(e.target.files)
      let that = this
      this.blobToDataURI(aBlob, function(res) {
        that.coverUrl = res
        that.option.img = res
      })
    },
    blobToDataURI(blob, callback) {
      var reader = new FileReader();
      reader.readAsDataURL(blob);
      reader.onload = function (e) {
        callback(e.target.result);
      }
    },
    async OSS(file){
      this.loading = true;
      const filename = file.name;

      // 获取STS token
      let credentials = await _api_stsTokenUpdata();

      // 创建对象
      this.ossClient = new OSS({
        region: "oss-cn-beijing",
        accessKeyId: credentials.data.accessKeyId,
        accessKeySecret: credentials.data.accessKeySecret,
        stsToken: credentials.data.securityToken,
        bucket: credentials.data.bucketName,
        secure: true,
      });

      this.ossClient
        .multipartUpload(filename, file, {
          parallel: 1,
          partSize: 1024 * 1024,
          progress: (p, cpt, res) => {
            // 获取上传进度。
            this.abortCheckpoint = cpt;
            console.log(p * 100);
            this.per = Math.floor(p * 100);
          },
        })
        .then((result) => {
          console.log(result)
          let index = result.res.requestUrls[0].lastIndexOf("?")
          if(index == -1){
            this.coverUrl = result.res.requestUrls[0]
            // this.option.img = this.coverUrl
          }else{
            this.coverUrl = result.res.requestUrls[0].substr(0,index)
            // this.option.img = this.coverUrl
          }
          this.$emit("giveruleCoverUrl", this.coverUrl)
          // e.target.value = ''
          this.dialogImg = false
          this.loading = false;
        })
        .catch(function (err) {
          console.log(err);
          this.loading = false;
        });
    },
  },
};
</script>
<style lang="scss" scoped>
.updataimg {
  display: flex;
  .updataimg_right {
    padding: 30px;
    h3 {
      font-weight: bolder;
      font-size: 16px;
    }
    p {
      margin: 0;
      font-size: 12px;
    }
  }
}
// 上传课程封面
.updataCourseImage {
  display: flex;
  justify-content: center;
  align-items: center;
  border: 1px dashed #87cefa;
  background-color: #fcfdfd;
}
.uploadImgwh{
  width: 512px;
  height: 288px;
}
.real_info_class {
  .el-checkbox__input .el-checkbox__inner {
    border-radius: 0;
  }
}
.file-image {
  width: 320px;
  height: 320px;
  font-size: 14px;
  border: 1px solid #cccccc;
  margin: 15px 0;
}

/* 截图 */
/* .cropper-content {} */
.cropper {
  width: 512px;
  height: 288px;
}
</style>

posted on 2022-12-29 13:01  苏舒  阅读(647)  评论(0编辑  收藏  举报