Vue2中使用vue-cropper插件进行裁剪案例与注意事项(较全面)

1,486 阅读2分钟

1.PC端截图插件的使用

主流的插件都有三种:Cropper.jsvue-cropper vue-cropper vue-img-cutter

vue-cropper官网

链接:github.com/xyxiao001/v…

本人使用的vue-cropper案例

https://blog.csdn.net/qq_41107231/article/details/109725839
https://juejin.cn/post/7189548709456773179
https://juejin.cn/post/7200625292855967805
https://juejin.cn/post/7032295846658097159
https://blog.csdn.net/weixin_46115860/article/details/107430614(详细)

  1. 安装
# npm 安装
npm install vue-cropper
  1. 引入
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
import VueCropper from 'vue-cropper'
Vue.use(VueCropper)
  1. 代码中使用
<vueCropper
  ref="cropper"
  :img="option.img"
  :outputSize="option.size"
  :outputType="option.outputType"
></vueCropper>
  1. 文档配置信息
名称功能默认值可选值
img裁剪图片的地址url 地址, base64, blob
outputSize裁剪生成图片的质量10.1 ~ 1
outputType裁剪生成图片的格式jpg (jpg 需要传入jpeg)jpeg, png, webp
info裁剪框的大小信息truetrue, false
canScale图片是否允许滚轮缩放truetrue, false
autoCrop是否默认生成截图框falsetrue, false
autoCropWidth默认生成截图框宽度容器的 80%0 ~ max
autoCropHeight默认生成截图框高度容器的 80%0 ~ max
fixed是否开启截图框宽高固定比例falsetrue, false
fixedNumber截图框的宽高比例[1, 1][ 宽度 , 高度 ]
full是否输出原图比例的截图falsetrue, false
fixedBox固定截图框大小不允许改变falsetrue, false
canMove上传图片是否可以移动truetrue, false
canMoveBox截图框能否拖动truetrue, false
original上传图片按照原始比例渲染falsetrue, false
centerBox截图框是否被限制在图片里面falsetrue, false
high是否按照设备的dpr 输出等比例图片truetrue, false
infoTruetrue 为展示真实输出图片宽高 false 展示看到的截图框宽高falsetrue, false
maxImgSize限制图片最大宽度和高度20000 ~ max
enlarge图片根据截图框输出比例倍数10 ~ max(建议不要太大不然会卡死的呢)
mode图片默认渲染方式containcontain , cover, 100px, 100% auto
  1. 内置的方法

通过 this.$refs.cropper 调用

属性

属性说明
this.$refs.cropper.cropW截图框宽度
this.$refs.cropper.cropH截图框高度

方法

方法说明
this.$refs.cropper.startCrop()开始截图
this.$refs.cropper.stopCrop()停止截图
this.$refs.cropper.clearCrop()清除截图
this.$refs.cropper.changeScale()修改图片大小 正数为变大 负数变小
this.$refs.cropper.getImgAxis()获取图片基于容器的坐标点
this.$refs.cropper.getCropAxis()获取截图框基于容器的坐标点
this.$refs.cropper.goAutoCrop自动生成截图框函数
this.$refs.cropper.rotateRight()向右边旋转90度
this.$refs.cropper.rotateLeft()向左边旋转90度
  1. 自己的案例效果

功能描述:

1)、放大、缩小、旋转、重置

2)、等比例放大缩小

3)、可以一打开固定宽高

4)、裁剪的背景可以更换,重点需要注意的是采用jpeg || png || webp

5)、等等很全,里面的配置都有,有的设置false

  1. 在对话框el-dialog内使用的
<template>
  
    <el-dialog
    width="50%"
    title="截图"
     v-if="dialogVisible2"
    :visible.sync="dialogVisible2"
    :before-close="handleClose2"
    class="innerDialog"
    :modal ="false"
    show-close
  >
  <!-- v-el-drag-dialog
      :modal="false"
      :close-on-click-modal="false"
   -->
    <div class="innerDiv">
      <!-- <CropperPage/> -->
      <div id="VueCropper">
        <div class="cropper-content">
          <div class="cropper-box">
            <div class="cropper">
              <vue-cropper
                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"
                :fixed="option.fixed"
                :fixedNumber="option.fixedNumber"
                :full="option.full"
                :fixedBox="option.fixedBox"
                :canMove="option.canMove"
                :canMoveBox="option.canMoveBox"
                :original="option.original"
                :centerBox="option.centerBox"
                :height="option.height"
                :infoTrue="option.infoTrue"
                :maxImgSize="option.maxImgSize"
                :enlarge="option.enlarge"
                :mode="option.mode"
                @imgLoad="imgLoad"
              >
              </vue-cropper>
            </div>
            <!--底部操作工具按钮-->
            <div class="footer-btn">
              <div class="scope-btn">
                <el-button
                  size="mini"
                  type="danger"
                  plain
                  icon="el-icon-zoom-in"
                  @click="changeScale(1)"
                  >放大</el-button
                >
                <el-button
                  size="mini"
                  type="danger"
                  plain
                  icon="el-icon-zoom-out"
                  @click="changeScale(-1)"
                  >缩小</el-button
                >
                <el-button size="mini" type="danger" plain @click="rotateLeft"
                  >↺ 左旋转</el-button
                >
                <el-button size="mini" type="danger" plain @click="rotateRight"
                  >↻ 右旋转</el-button
                >
              </div>
              <div class="upload-btn">
                <el-button size="mini" type="primary" @click="reset()"
                  >重置
                  <!-- <i class="el-icon-upload"></i> -->
                </el-button>
              </div>
              <div class="upload-btn">
                <el-button size="mini" type="success" @click="uploadImg('blob')"
                  >确定
                  <!-- <i class="el-icon-upload"></i> -->
                </el-button>
              </div>
              <div class="upload-btn">
                <el-button size="mini" @click="cancel()"
                  >取消
                  <!-- <i class="el-icon-upload"></i> -->
                </el-button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </el-dialog>
<script>
import { defineComponent } from "vue";
import { VueCropper } from "vue-cropper";
import store from "@/store/store.js";
// import elDragDialog from "@/utils/cropperIndex.js"; //引入拖动的自定义指令
// import    from
export default {
  name: "CropperPage",
  // directives: {
  //   elDragDialog
  // },
  data() {
    return {
      previews: {},
      option: {
        img: "", //裁剪图片的地址
        outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
        outputType: "jpeg", //裁剪生成图片的格式(jpeg || png || webp)
        info: false, //图片大小信息
        canScale: true, //图片是否允许滚轮缩放
        autoCrop: true, //是否默认生成截图框
        autoCropWidth: 687, //默认生成截图框宽度
        autoCropHeight: 550, //默认生成截图框高度
        fixed: true, //是否开启截图框宽高固定比例
        fixedNumber: [5, 4], //截图框的宽高比例
        full: true, //false按原比例裁切图片,不失真
        fixedBox: false, //固定截图框大小,不允许改变
        canMove: true, //上传图片是否可以移动
        canMoveBox: true, //截图框能否拖动
        original: false, //上传图片按照原始比例渲染
        centerBox: false, //截图框是否被限制在图片里面
        height: true, //是否按照设备的dpr 输出等比例图片
        infoTrue: false, //true为展示真实输出图片宽高,false展示看到的截图框宽高
        maxImgSize: 3000, //限制图片最大宽度和高度
        enlarge: 1, //图片根据截图框输出比例倍数
        mode: "contain" //图片默认渲染方式
      },
      productDialogVisible2: false,
      companyDialogVisible2: false,
      statusDialogVisible2: false
    };
  },

  computed: {
    dialogVisible2: {
      get() {
        return store.state.editDialog;
      },
      set(val) {}
    }
  },
 
  components: {
    VueCropper
  },
  methods: {
    handleClose2(e) {
      store.commit("changeeditDialog", false);
      store.commit("changeMask", false);
    },
    //初始化函数
    imgLoad(msg) {
      console.log("工具初始化函数=====" + msg);
    },
    //图片缩放
    changeScale(num) {
      num = num || 1;
      this.$refs.cropper.changeScale(num);
    },
    //向左旋转
    rotateLeft() {
      this.$refs.cropper.rotateLeft();
    },
    //向右旋转
    rotateRight() {
      this.$refs.cropper.rotateRight();
    },

    //选择图片
    selectImg(e) {
      let file = e.target.files[0];
      if (!/.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
        this.$message({
          message: "图片类型要求:jpeg、jpg、png",
          type: "error"
        });
        return false;
      }
      //转化为blob
      let reader = new FileReader();
      reader.onload = e => {
        let data;
        if (typeof e.target.result === "object") {
          data = window.URL.createObjectURL(new Blob([e.target.result]));
        } else {
          data = e.target.result;
        }
        this.option.img = data;
      };
      //转化为base64
      reader.readAsDataURL(file);
    },
    //上传图片
    uploadImg(type) {
      // console.log("type",type);
      let _this = this;
      this.$refs.cropper.getCropBlob(async data => {
        let formData = new FormData();
        formData.append("file", data, "DX.jpg");
        //调用axios上传 let {data: res} =
        await _this.$http
          .post(
            "http://api.700e.com/admin/common/putDestockingPublicFile",
            formData
          )
          .then(res => {
            // console.log("截图上传res", res);
            if (res.status === "success") {
              let imgPath = res.data.domain + res.data.path;

              if(store.state.category=="product"){
                // console.log("11111111111");
                this.$emit("imgPathFn", imgPath);
              }else{
                // console.log("222222222");
                this.$emit("imgPathFn2", imgPath);
              }
              
      store.commit("changeMask",false)
              store.commit("changeeditDialog", false);
              // this.ruleForm.productImgsURL.push(imgPath);
              // console.log(this.ruleForm);
            } else {
              this.$message.error("图片上传失败");
            }
          });

        store.commit("changeeditbtn1", false);
        store.commit("changeeditbtn2", false);
      });
    },
    reset() {
      this.$refs.cropper.reload();
      this.$refs.cropper.rotateClear();
    },
    cancel() {
      store.commit("changeeditbtn1", false);
      store.commit("changeeditbtn2", false);
      store.commit("changeeditDialog", false);
      store.commit("changeMask", false);
      console.log("正在点击外围");
    }
  },
  created(){
    
// var modal = document.getElementsByClassName('modal');
  },
  mounted() {
     
    this.option.img = store.state.editImgUrl;
  
  },
  
  updated() {
  
    this.option.img = store.state.editImgUrl;
  },
 
  destroyed(){
    // console.log("正在销毁");
    this.option.img = ""
    store.commit("changeeditImgUrl","")
  }
};
</script>
<style lang="less">
#VueCropper {
  width: 96%;
  height: 100%;
  // background-color: pink;
  position: absolute;
  z-index: 100;
}
.cropper-content {
  width: 100%;
  height: 86%;
  background-color: white;
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .cropper-box {
    flex: 1;
    width: 100%;
    .cropper {
      width: auto;
      height: 550px;
    }
  }

  .show-preview {
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
    .preview {
      overflow: hidden;
      border: 1px solid #67c23a;
      background: #cccccc;
    }
  }
}
.footer-btn {
  margin-top: 30px;
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .scope-btn {
    display: flex;
    display: -webkit-flex;
    justify-content: space-between;
    padding-right: 10px;
  }
  .upload-btn {
    flex: 1;
    -webkit-flex: 1;
    display: flex;
    display: -webkit-flex;
    justify-content: center;
  }
  .btn {
    outline: none;
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    -webkit-appearance: none;
    text-align: center;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    outline: 0;
    -webkit-transition: 0.1s;
    transition: 0.1s;
    font-weight: 500;
    padding: 8px 15px;
    font-size: 12px;
    border-radius: 3px;
    color: #fff;
    background-color: #409eff;
    border-color: #409eff;
    margin-right: 10px;
  }
}
</style>
// 覆盖层元素增加可穿透点击事件
.el-dialog__wrapper {

  pointer-events:none;
}
// 弹窗层元素不可穿透点击事件(不影响弹窗层元素的点击事件)
 .el-dialog{

  pointer-events:auto;
}


注意:此处的代码是针对自己做的遮罩层,点击返回上级,因为自己的业务需求,插件自身的带的遮罩层会盖住自己的遮罩层,此时就需要这几行css

遮罩层参考