vue-cropper 图片裁剪上传(antd-vue版本)

引入 vue-cropper 第三方插件

npm install vue-cropper

在 main.js 全局进入

import VueCropper from 'vue-cropper'
Vue.use(VueCropper)

封装图片裁剪模态框

components/Upload/CropperModal.vue

<template>
  <div id="create-cropper-modal">
    <a-modal
      :visible="visible"
      :title="options.title"
      :maskClosable="false"
      :confirmLoading="confirmLoading"
      :width="600"
      @cancel="handleCancel"
    >
      <a-row>
        <a-col :xs="24" :md="24" :style="{ height: '400px' }">
          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :fixedBox="options.fixedBox"
            :mode="cropperMode"
            @realTime="realTime"
          >
          </vue-cropper>
        </a-col>
        <!-- <a-col :xs="24" :md="12" :style="{ height: '250px' }">
        <div
          :class="
            options.previewsCircle
              ? 'avatar-upload-preview'
              : 'avatar-upload-preview_range'
          "
        >
          <img :src="previews.url" :style="previews.img" />
        </div>
      </a-col> -->
      </a-row>
      <template slot="footer">
        <a-button key="back" @click="handleCancel">取消</a-button>
        <a-button
          key="submit"
          type="primary"
          :loading="confirmLoading"
          @click="handleSumbit"
        >
          确定
        </a-button>
      </template>
    </a-modal>
  </div>
</template>

<script>
// import { Upgrad } from "corporatetrainingbundle/js/service";
export default {
  props: {
    //图片存储在oss上的上级目录名
    imgType: {
      type: String,
      default: "",
    },
    fileName: {
      type: String, // 文件名
      default: "",
    },
    cropperMode: {
      // 图片渲染方式
      type: String,
      default: "contain",
    },
  },
  mounted() {},
  data() {
    return {
      visible: false,
      img: null,
      confirmLoading: false,
      options: {
        img: "", //裁剪图片的地址
        autoCrop: true, //是否默认生成截图框
        autoCropWidth: 200, //默认生成截图框宽度
        autoCropHeight: 200, //默认生成截图框高度
        fixedBox: true, //是否固定截图框大小 不允许改变
        previewsCircle: false, //预览图是否是原圆形
        title: "修改图片",
      },
      previews: {},
      url: {
        upload: "/sys/common/saveToImgByStr",
      },
    };
  },
  methods: {
    edit(record) {
      this.visible = true;
      this.options = Object.assign({}, this.options, record);
    },
    // 取消截图
    handleCancel() {
      this.confirmLoading = false;
      this.visible = false;
      this.$emit("cropper-no");
    },
    // 确认截图
    handleSumbit() {
      this.confirmLoading = true;
      // 获取截图的base64 数据
      this.$refs.cropper.getCropData(async (data) => {
        const file = this.dataURLtoFile(data, this.fileName);
        let formData = new window.FormData();
        formData.append("file", file);
        // 调用后端接口上传裁剪后图片,获取图片url传递给组件表单和回显
        // formData.append("token", $("#upload_token").val());
        // try {
        //   const { id, url } = await Upgrad.uploadImageApi(formData);
        //   this.$emit("cropper-ok", id, url);
        // } catch (error) {
        //   this.$message.error("网络异常,请稍后再试!");
        // } finally {
        //   this.visible = false;
        //   this.confirmLoading = false;
        // }
      });
    },
    //移动框的事件
    realTime(data) {
      this.previews = data;
    },
    // base 64 转成二进制文件流
    dataURLtoFile(dataurl, filename) {
      var arr = dataurl.split(","),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, { type: mime });
    },
  },
};
</script>
<style lang="less" scoped>
#create-cropper-modal {
  .avatar-upload-preview_range,
  .avatar-upload-preview {
    position: absolute;
    top: 50%;
    transform: translate(50%, -50%);
    width: 100%;
    height: 100%;
    border-radius: 50%;
    box-shadow: 0 0 4px #ccc;
    overflow: hidden;
    img {
      background-color: red;
      height: 100%;
    }
  }
  .avatar-upload-preview_range {
    border-radius: 0;
  }
}
</style>

封装上传组件

components/Upload/CropperUpload.vue

<template>
  <div id="create-ant-upload-preview">
    <div class="ant-upload-preview">
      <div class="avatatImg">
        <a-upload
          name="avatar"
          listType="picture-card"
          :showUploadList="false"
          :beforeUpload="beforeUpload"
          :customRequest="function () {}"
          @change="handleChange"
          :accept="accept"
        >
          <img
            class="upload_img"
            v-if="imageUrl"
            :src="imageUrl"
            alt="avatar"
          />
          <div v-else>
            <a-icon :type="loading ? 'loading' : 'plus'" />
            <div class="ant-upload-text">上传</div>
          </div>
        </a-upload>
        <div class="text">
          <div>{{ avatarText }}</div>
        </div>
      </div>
      <!-- 引入裁剪组件 -->
      <CropperModal
        ref="CropperModal"
        :imgType="imgType"
        :fileName="fileName"
        :cropperMode="cropperMode"
        @cropper-no="handleCropperClose"
        @cropper-ok="handleCropperSuccess"
      />
    </div>
  </div>
</template>

<script>
import CropperModal from "./CropperModal";
export default {
  components: { CropperModal },
  props: {
    //图片裁切配置
    options: {
      type: Object,
      default: function () {
        return {
          autoCrop: true, //是否默认生成截图框
          autoCropWidth: 1029, //默认生成截图框宽度
          autoCropHeight: 480, //默认生成截图框高度
          fixedBox: true, //是否固定截图框大小 不允许改变
          previewsCircle: false, //预览图是否是原圆形
          title: "修改图片",
        };
      },
    },
    avatarText: {
      type: String,
      default:
        "支持jpg, gif, png格式的图片, 建议最小尺寸480x270,大小不能超过2M",
    },
    // 上传图片的大小,单位M
    imgSize: {
      type: Number,
      default: 2 * 1024 * 1024,
    },
    //图片存储在oss上的上级目录名
    imgType: {
      type: String,
      default: "",
    },
    // 图片地址
    imageUrl: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      isError: false,
      accept: "image/png,image/jpg,image/jpeg,image/gif",
      fileName: "", // 文件名
      loading: false,
      isStopRun: false,
      cropperMode: "contain", // 图片渲染方式
    };
  },
  methods: {
    //从本地选择文件
    handleChange(info) {
      if (this.isError || this.isStopRun) {
        return;
      }
      this.loading = info.file.status;
      this.fileName = info.file.name;
      this.getBase64(info.file.originFileObj, (imageUrl) => {
        const target = Object.assign({}, this.options, {
          img: imageUrl,
        });
        this.$refs.CropperModal.edit(target);
      });
    },
    // 上传之前 格式与大小校验
    beforeUpload(file) {
      // this.$emit("avatarLoadingFn", true);
      this.isError = false;
      this.isStopRun = false;
      const imgTypeArr = ["image/jpeg", "image/png", "image/jpg", "image/gif"];
      const isJpgOrPng = imgTypeArr.includes(file.type);
      if (!isJpgOrPng) {
        this.isError = true;
        this.$message.error("不能上传其他类型的图片");
        return;
      }

      const isSizeLegal = file.size <= this.imgSize;
      if (!isSizeLegal) {
        this.$message.error("图片大小超过限制");
        this.isStopRun = true;
        this.isError = true;
        return;
      }

      // 获取上传图片尺寸
      var reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => {
        var img = new Image();
        img.src = reader.result;
        img.onload = () => {
          // 1、先根据图片裁剪的尺寸
          if (this.options.autoCropWidth > this.options.autoCropHeight) {
            // 2、再根据上传图片尺寸
            this.cropperMode = this.options.autoCropWidth + "px auto";
          } else {
            if (img.width >= img.height) {
              this.cropperMode = "auto " + this.options.autoCropHeight + "px";
            } else {
              this.cropperMode = this.options.autoCropWidth + "px auto";
            }
          }
        };
      };

      return isJpgOrPng;
    },
    //获取服务器返回的地址
    handleCropperSuccess(id, url) {
      //将返回的数据回显
      this.loading = false;
      this.$emit("avatarfn", id, url);
    },
    // 取消上传
    handleCropperClose() {
      this.loading = false;
    },
    getBase64(img, callback) {
      if (img) {
        const reader = new FileReader();
        reader.addEventListener("load", () => callback(reader.result));
        reader.readAsDataURL(img);
      }
    },
  },
};
</script>
<style lang="less" scoped>
#create-ant-upload-preview {
  .avatar-upload-wrapper {
    height: 180px;
    width: 100%;
  }
  //更改上传组件宽高
  /deep/ .ant-upload-select {
    width: 198px;
    height: 108px;
  }

  .ant-upload-preview {
    background-color: #fff;

    .ant-upload-select-picture-card i {
      font-size: 14px;
      color: #5e6166;
    }
    .upload_img {
      width: 100%;
    }
    .ant-upload-select-picture-card .ant-upload-text {
      font-size: 14px;
      margin-top: 8px;
      color: #5e6166;
    }
  }
  .ant-upload-picture-card-wrapper {
    width: auto;
  }
  .avatar-uploader > .ant-upload {
    width: 128px;
    height: 128px;
  }
  .avatatImg {
    display: flex;
    flex-direction: column;
    .text {
      div {
        line-height: 22px !important;
        font-weight: 600;
        color: #919399;
        font-size: 14px;
        font-style: normal;
        font-weight: 400;
      }
    }
  }
}
</style>

页面引入使用

App.vue

<template>
  <div>
    <CropperUpload
      :imageUrl="coverUrl"
      :options="coverOptions"
      @avatarfn="coverUrlFn"
      avatarText="支持jpg, gif, png格式的图片, 建议最小尺寸480x270,大小不能超过2M"
    />
  </div>
</template>
<script>
import CropperUpload from "./components/Upload/CropperUpload.vue";
export default {
  data() {
    return {
      form: {},
      coverUrl: "",
      coverOptions: {
        autoCrop: true, //是否默认生成截图框
        autoCropWidth: 480, //默认生成截图框宽度
        autoCropHeight: 270, //默认生成截图框高度
        fixedBox: true, //是否固定截图框大小 不允许改变
        previewsCircle: false, //预览图是否是原圆形
        title: "修改图片",
      },
    };
  },
  created() {},
  mounted() {},
  methods: {
    coverUrlFn(id, url) {
      this.coverUrl = url;
      this.form.coverId = id;
    },
  },
  components: {
    CropperUpload,
  },
};
</script>

效果图: 

上传组件效果图

裁剪组件效果图

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要实现Vue图片裁剪上传,可以使用vue-cropper组件。以下是一个简单的实现过程: 1. 首先,在Vue项目中安装vue-cropper组件。可以使用npm或yarn来安装,命令如下: ``` npm install vue-cropper ``` 2. 在需要使用图片裁剪上传的组件中,引入vue-cropper组件。可以在组件的template中添加以下代码: ```html <template> <div> <vue-cropper ref="cropper" :src="imageSrc" :guides="true" :view-mode="1" :auto-crop-area="0.8" ></vue-cropper> <button @click="cropImage">裁剪上传</button> </div> </template> ``` 3. 在组件的script部分,添加必要的代码。首先,引入vue-cropper组件: ```javascript import VueCropper from 'vue-cropper' ``` 然后,在components中注册vue-cropper组件: ```javascript components: { VueCropper }, ``` 接下来,定义data中的imageSrc属性,用于展示需要裁剪图片: ```javascript data() { return { imageSrc: '图片路径' } }, ``` 4. 实现裁剪上传功能。在methods中,定义cropImage方法: ```javascript methods: { cropImage() { const cropper = this.$refs.cropper const imageData = cropper.getCroppedCanvas().toDataURL('image/jpeg') // 将imageData发送到后端进行上传处理 // ... } }, ``` 在cropImage方法中,通过this.$refs.cropper获取vue-cropper组件实例,并使用getCroppedCanvas方法获取裁剪后的图片数据。最后,将图片数据发送到后端进行上传处理。 这样,就实现了Vue图片裁剪上传的功能。你可以根据具体的需求,自定义vue-cropper组件的属性和方法,来实现更多的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

零凌林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值