vue2中使用vue-cropper实现图剪裁效果

图片剪裁效果图:

剪裁组件封装如下:

<!-- 原版-剪裁 -->

<template>

  <div :class="$options.name">

    <el-dialog :visible.sync="dialogVisible" width="742px" :before-close="handleClose">

      <div class="cropper-container">

        <div class="cropper-el">

          <div style="text-align: left; margin-bottom: 5px; font-weight: 600;">剪裁</div>

          <vue-cropper ref="cropper" :img="cropperImg" :output-size="option.size" :output-type="option.outputType"

            :info="true" :full="option.full" :can-move="option.canMove" :can-move-box="option.canMoveBox"

            :fixed-box="option.fixedBox" :original="option.original" :auto-crop="option.autoCrop"

            :auto-crop-width="option.autoCropWidth" :auto-crop-height="option.autoCropHeight"

            :center-box="option.centerBox" :high="option.high" :info-true="option.infoTrue" @realTime="realTime"

            :enlarge="option.enlarge" :fixed="option.fixed" :fixed-number="fixedNumber" />

       

        </div>

        <!-- 预览 -->

        <div class="prive-el">

          <div style="text-align: left; padding-left: 25px; margin-bottom: 5px;  font-weight: 600;">预览</div>

          <div class="prive-style"

            :style="{ 'height': '300px', 'overflow': 'hidden', 'margin': '0 25px', 'display': 'flex', 'align-items': 'center' }">

            <div class="preview" :style="previews.div">

              <img :src="previews.url" :style="previews.img">

            </div>

          </div>

          <el-button @click="uploadBth" v-if="option.img">重新上传</el-button>

        </div>

     

      </div>

      <span slot="footer" class="dialog-footer">

        <el-button @click="handleClose">取 消</el-button>

        <el-button type="primary" @click="saveImg">确 定</el-button>

      </span>

    </el-dialog>

  </div>

</template>


<script>

import { VueCropper } from 'vue-cropper';

export default {

  name: 'Cropper',

  components: {

    VueCropper

  },

  props: {

    dialogVisible: {

      type: Boolean,

      default: false

    },

    imgType: {

      type: String,

      default: 'blob'

    },

    cropperImg: {

      type: String,

      default: ''

    },

    fixedNumber: {

      type: Array,

      default: () => [1, 1]

    }

  },

  data() {

    return {

      previews: {},

      option: {

        img: '', // 裁剪图片的地址

        size: 1, // 裁剪生成图片的质量

        full: false, // 是否输出原图比例的截图 默认false

        outputType: 'png', // 裁剪生成图片的格式 默认jpg

        canMove: true, // 上传图片是否可以移动

        fixedBox: false, // 固定截图框大小 不允许改变

        original: false, // 上传图片按照原始比例渲染

        canMoveBox: true, // 截图框能否拖动

        autoCrop: true, // 是否默认生成截图框

        // 只有自动截图开启 宽度高度才生效

        // autoCropWidth: 200, // 默认生成截图框宽度

        // autoCropHeight: 150, // 默认生成截图框高度

        autoCropWidth: 1920, // 默认生成截图框宽度

        autoCropHeight: 1080, // 默认生成截图框高度


        centerBox: false, // 截图框是否被限制在图片里面

        high: false, // 是否按照设备的dpr 输出等比例图片

        enlarge: 10, // 图片根据截图框输出比例倍数

        mode: 'contain', // 图片默认渲染方式

        maxImgSize: 2000, // 限制图片最大宽度和高度

        limitMinSize: [100, 120], // 更新裁剪框最小属性

        infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高

        fixed: true, // 是否开启截图框宽高固定比例  (默认:true)

        // fixedNumber: [16, 9] // 截图框的宽高比例

      }

    };

  },

  methods: {

    // 裁剪时触发的方法,用于实时预览

    realTime(data) {

      this.previews = data;

    },

    // 重新上传

    uploadBth() {

      this.$emit('update-cropper');

    },

    // 取消关闭弹框

    handleClose() {

      this.$emit('colse-dialog', false);

    },

    // 获取裁剪之后的图片,默认blob,也可以获取base64的图片

    saveImg() {

      if (this.imgType === 'blob') {

        this.$refs.cropper.getCropBlob(data => {

          this.$emit('upload-img', data);

        });

      } else {

        this.$refs.cropper.getCropData(data => {

          this.uploadFile = data;

          this.$emit('upload-img', data);

        });

      }

    }

  }

};

</script>


<style lang="scss" scoped>

::v-deep {

  .el-dialog__footer {

    padding-top: 50px;

  }

}


.Cropper {

  .cropper-el {

    height: 300px;

    width: 300px;

  }


  .cropper-container {

    display: flex;

    justify-content: space-between;


    .prive-el {

      height: 164px;

      width: 94px;

      flex: 1;

      text-align: center;


      .prive-style {

        margin: 0 auto;

        flex: 1;

        -webkit-flex: 1;

        display: flex;

        display: -webkit-flex;

        justify-content: center;

        -webkit-justify-content: center;

        overflow: hidden;

        background: #ededed;

        margin-left: 40px;

      }


      .preview {

        overflow: hidden;

        border: 1px solid #999;

      }


      .el-button {

        margin-top: 20px;

      }

    }

  }

}

</style>

将上面剪裁组件与Element UI的el-upload封装如下:

<template>

  <div :class="$options.name">

    <el-upload v-show="!resultImg" class="upload-el" :accept="accept" ref="fileUpload" :name="fileName" :action="action"

      :data="uploadData" :on-change="selectChange" :show-file-list="false" :auto-upload="false"

      :http-request="httpRequest">

      <div>

        <!-- 上传的+号icon -->

        <!-- <span class="icon upload-icon" /> -->

        <el-button>{{ uploadBtnName }}</el-button>

      </div>

      <div slot="tip" class="el-upload__tip">

        {{ uploadTip }}

      </div>

    </el-upload>


    <figure v-show="resultImg" class="result-img">

      <el-button

        style="border: 1px solid #DCDFE6; width: 100px; height: 30px; display: flex; justify-content: center; align-items: center;"

        @click="updateCropper">重新上传</el-button>

      <!-- <img :src="lookImgPath + resultImg" style="border: 1px solid #999; width: 150px; height: 80px;"> -->

    </figure>

    <cropper v-if="showCropper" :dialog-visible="showCropper" :cropper-img="cropperImg" @update-cropper="updateCropper"

      @colse-dialog="closeDialog" @upload-img="uploadImg" :fixedNumber="fixedNumber" />

  </div>

</template>


<script>

import Cropper from './Cropper.vue';

import axios from '@/components/ImgPrune/common/axios';

import { loading } from '@/components/ImgPrune/common';

export default {

  name: 'UploadImg',

  components: {

    Cropper

  },


  props: {

    // 图片剪裁比例

    fixedNumber: {

      type: Array,

      default: () => [1, 1]

    },


    // 图片服务器上传地址

    action: {

      type: String,

      default: '',

    },


    // 查看图片路径

    lookImgPath: {

      type: String,

      default: '',

    },


    // 图片服务器上传接口名称

    fileName: {

      type: String,

      default: 'formFile'

    },


    // 上传按钮文字

    uploadBtnName: {

      type: String,

      default: '上传',

    },


    // 上传文件类型限制(如:.jpg,.webp)

    accept: {

      type: String,

      default: ''

    },


    // 上传按钮下面提示的信息

    uploadTip: {

      type: String,

      default: '',

    },


    // 上传图片 大小限制

    imgUploadSize: {

      type: Number,

      default: 5,

    }

  },


  data() {

    return {

      uploadData: { // 上传需要的额外参数

        // siteId: 1,

        // source: 1,

        // fileName: ''

      },

      // action: 'https://jsonplaceholder.typicode.com/posts/', // 上传地址,必填 原版

      cropperImg: '', // 需要裁剪的图片

      showCropper: false, // 是否显示裁剪框

      uploadFile: '', // 裁剪后的文件

      resultImg: '' // 上传成功,后台返回的路径

    };

  },


  methods: {

    // submit 之后会触发此方法

    httpRequest(request) {

      console.log('request', request)

      const { action, data, filename } = request;


      // 新建formDate对象

      let formData = new FormData();


      for (let key in data) {

        formData.append(key, data[key]);

      }


      // 文件单独push,第三个参数指定上传的文件名

      formData.append(filename, this.uploadFile, data.fileName);

      loading.start(); // 上传中的loading

      axios.baseAxios({

        headers: {

          contentType: 'multipart/form-data' // 需要指定上传的方式

        },

        url: action,

        method: 'post',

        data: formData,

        timeout: 200000000 // 防止文件过大超时

      }).then(({ data: resp }) => {

        console.log('resp', resp)

        loading.close();


        this.$emit('success-img-path', resp);

        this.resultImg = resp; // 上传成功后展示的图片


        let popupNum = document.getElementsByClassName('el-message').length;


        // 防止同时多个弹框问题

        if (popupNum == 0) {

          this.$message.success('图片上传成功');

        }


        this.showCropper = false;

      }).catch(err => {

        loading.close();

        console.log(err);

      });

    },


    // 选择文件

    selectChange(file) {

      const { raw, name } = file;

      console.log('raw', file, raw);

      this.openCropper(raw);

      this.uploadData.fileName = name; // 文件名字(需要传递-否则服务器异常)

    },


    /**

     * @param {file} 上传的文件

      */

    openCropper(file) {

      console.log('图片大小控制', file);

      var files = file;

      let isLt5M = (files.size / 1024 / 1024) > this.imgUploadSize;

      console.log('当前图片兆为:', files.size / 1024 / 1024); // size为字节:先/1024转为KB,再/1024转为兆

      // let isLt5M = files.size > (5 << 20); // 原版

      if (isLt5M) {

        this.$message.error(`请上传${this.imgUploadSize}M内的图片`);

        return false;

      }

      var reader = new FileReader();

      console.log('reader', reader);


      reader.onload = e => {

        console.log('e', e);

        let data;


        if (typeof e.target.result === 'object') {

          // 把Array Buffer转化为blob 如果是base64不需要

          data = window.URL.createObjectURL(new Blob([e.target.result]));

        } else {

          data = e.target.result;

        }


        console.log('data', data);

        this.cropperImg = data;

      };

      // 转化为base64

      // reader.readAsDataURL(file)

      // 转化为blob

      reader.readAsArrayBuffer(files);

      this.showCropper = true;

    },


    // 上传图片(file为剪裁后的图片)

    uploadImg(file) {

      console.log('剪裁后的图片', file);

      this.uploadFile = file;

      this.$refs.fileUpload.submit();

      this.$refs.fileUpload.clearFiles(); // 每次submit 都情况下文件列表,避免重复上传之前的文件(多次上传问题)

    },


    // 更新图片

    updateCropper() {

      this.$refs.fileUpload.$children[0].$el.click();

    },


    // 关闭窗口

    closeDialog() {

      this.showCropper = false;

    }

  }

};

</script>


<style lang="scss" scoped>

.UploadImg {

  .el-upload {

    display: block;

    width: 100px;

    margin: 30px auto 0;

  }


  .upload-icon {

    display: block;

    margin: 0 auto;

    height: 44px;

    width: 52px;

    background-image: url(~@/assets/img/upload-image.png);

    background-position: 100% 100%;

    margin-bottom: 20px;

  }


  .video-image {

    display: flex;


    figure {

      width: 100px;


      img {

        width: 100%;

        display: block;

      }

    }

  }

}


.result-img {

  display: flex;


  >img {

    margin-left: 15px;

  }

}

</style>

对应组件中使用如下:

import UploadImg from '@/components/ImgPrune/components/UploadImg'


<div class="right-container" style="width: 100%;">

                            <div class="ul-components" style="width: 100%; display: flex;">


                                <upload-img :action="devImgPathPrefox" :lookImgPath="devImgPathPrefoxLook"

                                    :fixedNumber="fixedNumber" :fileName="fileName" :uploadBtnName="uploadBtnName"

                                    :accept="accept" :uploadTip="uploadTip" :imgUploadSize="imgUploadSize"

                                    @success-img-path="successImgPathCover" />


                                <div class="img-container"

                                    v-if="operateType != 'add' || (operateType == 'add' && ruleForm.fileListCover.length > 0)">

                                    <img :src="this.devImgPathPrefoxLook + ruleForm.fileListCover[0]"

                                        style="border: 1px solid #999; height: 80px; width: 150px; margin-left: 15px;">

                                </div>

                            </div>

                        </div>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值