zoukankan      html  css  js  c++  java
  • 10.vue+elementUI+vue-cropper图片裁剪并上传

    最终达到这样的效果:

    以下省略了一些简单的代码,比如组件引入等

    1、引入element ui上传组件

     <upload-img :pic="form.bgImage" @getUrlFn="getImgUrl" @modalShowFn="getModalStatus"></upload-img>

    2、uploadImg组件内容

    <template>
      <div>
        <!-- accept="image/gif, image/jpeg,image/jpg,image/png,image/bmp" -->
        <el-upload
          class="avatar-uploader"
          v-loading="loading"
          :action="action"
          :data="uploadData"
          :show-file-list="false"
          name="file"
          :on-success="handleAvatarSuccess"
          :on-progress="handProcess"
          :http-request="picUpload"
          :before-upload="beforeAvatarUpload"
        >
          <img v-if="imageUrl" :src="imageUrl" class="avatar" />
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
        <div v-if="maskBox" @mouseleave="maskBox = false" class="mask">
          <i @click="handleRemove" style="font-size: 24px" class="el-icon-delete"></i>
        </div>
      </div>
    </template>
    <script>
    export default {
      props: {
        pic: {
          type: String,
          default: ''
        }
      },
      data() {
        return {
          action: '上传地址',
          disabled: false,
          uploadData: {
            file: '',
            project: ''
          },
          imageUrl: '',
          loading: false,
          maskBox:false,
        }
      },
      watch: {
        pic: {
          handler(newval, oldval) {
            console.log(newval)
            if (newval) {
              this.imageUrl = newval
            }
          },
          deep: true
        }
      },
      created() {
        this.imageUrl = this.picUrl
      },
      methods: {
        // 图片上传前触发裁剪组件
        // 将图片读出并在完成时触发裁剪
        picUpload(option) {
          let file = option.file
          let reader = new FileReader();
          if (file) {
            reader.readAsDataURL(file)
          }
         reader.onload = () => {
            let src = reader.result
            // this.cropperShow = true
            // this.cropperImg = src
            let obj = {
              cropperShow:true,
              cropperImg:src
            }
            this.$emit("modalShowFn",obj)
          }
        },
        handleRemove(file) {
          this.imageUrl = '';
          this.maskBox = false;
          this.$emit('getUrlFn', '')
        },
        handleAvatarSuccess(res, file) {
          this.imageUrl = res.browser;
          this.loading = false;
          this.$emit('getUrlFn', res.browser, file.raw)
    
        },
        beforeAvatarUpload(file) {
          const isLt10M = file.size / 1024 / 1024 < 10;
          const isJPG = file.type === 'image/jpeg' || file.type === 'image/gif' || file.type === 'image/jpg' || file.type === 'image/bmp' || file.type === 'image/png';
          if (!isLt10M) {
            this.$message.error('上传图片大小不能超过 10MB!');
          }
          if (!isJPG) {
            this.$message.error('上传头像图片只能是 JPG/JPEG/GIF/BMP 格式!');
          }
          return isJPG && isLt10M;
        },
        handProcess(event, file) {
          this.loading = true;
    
        }
      }
    }
    </script>
    <style scope>
    .avatar-uploader .el-upload {
      border-radius: 6px;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      border: 1px solid #dcdee2;
    }
    .avatar-uploader .el-upload:hover {
      border-color: #409eff;
    }
    .avatar-uploader-icon {
      font-size: 28px;
      color: #8c939d;
       200px;
      height: 200px;
      line-height: 148px;
      text-align: center;
    }
    .avatar {
       200px;
      height: 200px;
      display: block;
      position: relative;
      z-index: 99;
    }
    .el-icon-plus:before {
      line-height: 200px;
    }
    </style>

    3、安装vue-cropper,在页面中引入vue-cropper

    npm install vue-cropper --save
    import vueCropper from "vue-cropper"

    4、用vue-cropper封装图片裁剪组件

    组件放入modal中

     <Modal v-model="isShowCropper" class="cropperModal" :closable="false" width="530px">
          <div class="cropperModalBody" style="520px;height:350px">
            <img-cropper
              :cropperOption="cropperOption"
              :img="cropperImg"
              :file="cropperFile"
              @cropperFinish="postUploadFile"
              @close="()=>{isShowCropper=false}"
            ></img-cropper>
          </div>
          <div slot="footer"></div>
        </Modal>

    一些方法

     getImgUrl(url) {
          this.form.bgImage = url
        },
        getModalStatus(obj) {
          this.cropperImg = obj.cropperImg;
          this.isShowCropper = obj.cropperShow;
        },
    
        // 文件上传-接口-上传文件
        postUploadFile(blob) {
          //将blob转换为file
          let file = new File([blob], '图片.png', { type: 'image/png', lastModified: Date.now() });
          file.uid = Date.now();
          var fd = new FormData();
          fd.append("file", file, "图片.png");
          fd.append("project", "micropark_coordination");
    
          uploadFile(fd).then(res => {
            if (res.code === 200) {
              this.form.bgImage = res.browser;
              //  this.$refs.upload.clearFiles()
              this.isShowCropper = false;
              this.cropperImg = null;
              this.cropperFile = {};
            }
          });
        }

    5、img-cropper组件内容

    <template>
      <div class="vue-cropper-box">
        <div class="vue-cropper-header">
          <p class="title" style="font-size:16px">
            图片裁剪
            <Icon type="ios-close" @click="close()" />
          </p>
        </div>
        <div class="vue-cropper-operate">
          <button class="basicButton" @click="cropperChangeScale(1)">放大</button>
          <button class="basicButton" @click="cropperChangeScale(-1)">缩小</button>
          <button class="basicButton" @click="cropperRotateLeft">左旋转</button>
          <button class="basicButton" @click="cropperRotateRight">右旋转</button>
          <!-- <button class="basicButton" @click="cropperDown('blob')">下载</button> -->
          <button class="basicButton" @click="cropperFinish">确定裁剪</button>
        </div>
        <div class="vue-cropper-content" style="500px;height:310px">
          <vueCropper
            ref="cropper"
            :img="img"
            :outputSize="cropperOption.outputSize"
            :outputType="cropperOption.outputType"
            :info="cropperOption.info"
            :full="cropperOption.full"
            :canMove="cropperOption.canMoveBox"
            :canMoveBox="cropperOption.canMoveBox"
            :original="cropperOption.original"
            :canScale="cropperOption.canScale"
            :autoCrop="true"
            :autoCropWidth="200"
            :autoCropHeight="200"
            :fixedBox="true"
            :fixed="cropperOption.fixed"
            :fixedNumber="cropperOption.fixedNumber"
            :centerBox="cropperOption.centerBox"
            :infoTrue="cropperOption.infoTrue"
            @realTime="realTime"
            @imgLoad="imgLoad"
          ></vueCropper>
        </div>
      </div>
    </template>
    <script>
    import vueCropper from "vue-cropper"
    export default {
      name: 'by-cropper',
      components: { vueCropper },
      // inject: ['reload'],
      filters: {},
      props: {
        file: {
          default: () => { },
          required: true
        },
        img: {
          default: "",
          required: true
        },
        cropperOption: {
          default: () => ({
            // img: '', // 裁剪图片的地址
            info: true, // 裁剪框的大小信息
            outputSize: 1, // 裁剪生成图片的质量
            full: false, // 输出原图比例截图 props名full
            outputType: 'png', // 裁剪生成图片的格式
            canMove: true, // 能否拖动图片
            original: false, // 上传图片是否显示原始宽高
            canMoveBox: true, // 能否拖动截图框
            canScale: false, // 图片是否允许滚轮缩放
            autoCrop: true, // 是否默认生成截图框
            autoCropWidth: 200, // 默认生成截图框宽度
            autoCropHeight: 200, // 默认生成截图框高度
            fixedBox: true, // 截图框固定大小
            fixed: true, // 是否开启截图框宽高固定比例
            fixedNumber: [1, 1], // 截图框的宽高比例
            original: false, // 上传图片按照原始比例渲染
            centerBox: true, // 截图框是否被限制在图片里面
            infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
          })
        }
      },
      data() {
        return {
        };
      },
      computed: {
        // computeFunction() {
        //     return value;
        // }
      },
      watch: {
      },
      created() {
        // this.init();
      },
      mounted() {
        this.init();
      },
      methods: {
        init() {
          this.cropperOption.img = this.file
        },
    
        cropperChangeScale(num) {
          num = num || 1;
          this.$refs.cropper.changeScale(num);
        },
    
        // 左旋转
        cropperRotateLeft() {
          this.$refs.cropper.rotateLeft();
        },
    
        // 右旋转
        cropperRotateRight() {
          this.$refs.cropper.rotateRight();
        },
    
        // 下载图片
        cropperDown(type) {
          let aLink = document.createElement('a');
          aLink.download = 'author-img';
          if (type === 'blob') {
            this.$refs.cropper.getCropBlob(data => {
              this.downImg = window.URL.createObjectURL(data);
              aLink.href = window.URL.createObjectURL(data);
              aLink.click();
            });
          } else {
            this.$refs.cropper.getCropData(data => {
              this.downImg = data;
              aLink.href = data;
              aLink.click();
            });
          }
        },
    
        // 确定裁剪
        cropperFinish(type) {
          if (type === 'Blob') {
            this.$refs.cropper.getCropBlob((data) => {
              let file = data;
              file.name = this.file.name;
              this.$emit('cropperFinish', file, data);
            });
    
          } else {
            this.$refs.cropper.getCropData(data => {
    
              // 将剪裁后base64的图片转化为file格式
              let file = this.convertBase64UrlToBlob(data);
              file.name = this.file.name;
    
              this.$emit('cropperFinish', file, data);
            });
          }
    
        },
    
        // 将base64的图片转换为file文件
        convertBase64UrlToBlob(urlData) {
          let bytes = window.atob(urlData.split(',')[1]); // 去掉url的头,并转换为byte
          // 转化为base64
          // reader.readAsDataURL(file)
          // 转化为blob
          // 处理异常,将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' });
        },
    
        // 实时预览函数
        realTime(data) {
          // console.log('realTime');
        },
    
        // 图片已加载
        imgLoad(msg) {
          // console.log('imgLoad');
          // console.log(msg);
        },
        close() {
          this.$emit('close');
        }
      }
    };
    </script>
    <style lang="less" scope>
    // 基础按钮
    .basicButton {
      font-size: 16px;
       100px;
      padding: 8px 10px;
      // line-height: 0.4rem;
      border: none;
      border-radius: 20px;
      color: #fff;
      background: #5cadff;
      outline: none;
    
      &:not(:last-child) {
        margin-right: 20px;
      }
    }
    .vue-cropper-header {
      .title {
        font-weight: 600;
        display: flex;
        justify-content: space-between;
        padding-top: 20px;
        margin-bottom: 10px;
        .ivu-icon .ivu-icon-ios-close {
          font-size: 20px;
        }
      }
    }
    /* 图片裁剪工具 */
    .vue-cropper-box {
      z-index: 3001;
      position: absolute;
      top: 0;
      background: #fff;
    
      .vue-cropper-operate {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0.2rem;
      }
    
      .vue-cropper-content {
        position: relative;
        overflow-y: auto;
    
        .vue-cropper {
          position: absolute;
        }
      }
    }
    </style>
  • 相关阅读:
    javascript命名规范
    angularjs指令参数transclude
    angular中的compile和link函数
    angularjs中的directive scope配置
    sublime text3同时编辑多行
    jquery中on/delegate的原理
    defered,promise回顾
    导航栏滚动到顶部后固定
    angularjs揭秘
    $stateParams
  • 原文地址:https://www.cnblogs.com/janet11/p/12505263.html
Copyright © 2011-2022 走看看