vue实现图片裁剪后上传

(编辑:jimmy 日期: 2024/11/9 浏览:2)

本文实例为大家分享了vue实现图片裁剪后上传的具体代码,供大家参考,具体内容如下

一、背景

目前负责的系统(商城后台管理系统)里面有这么一个需求,为了配合前台的展示,上传的商品图片比较必须是1:1的正方形。(其它地方有时会有5:4或者16:9的需求,但较少)。所以需要对上传的图片先进行裁剪,并且按要求只能裁剪为1:1,然后在进行上传。

当然,为了兼容系统其它地方有5:4或者16:9的图片比例需求,需要给出一个参数,可以随时控制图片裁剪的比例。

二、使用什么插件实现

使用 vue-cropper 显示,该插件是基于 cropper 的二次封装,简单小巧,更合适vue项目。注意:功能没有 cropper 强大。

三、使用 cropper

3.1 封装一下cropper, 配置自己想要的参数

<template>
 <div class="Cropper">
 <el-dialog
  :visible.sync="dialogVisible"
  width="740px"
  title="图片裁剪"
  :before-close="handleClose"
  :close-on-click-modal="false">
  <div
  class="cropper-container">
  <div class="cropper-el">
   <vue-cropper
   ref="cropper"
   :img="cropperImg"
   :output-size="option.size"
   :output-type="option.outputType"
   :info="true"
   :can-move="option.canMove"
   :can-move-box="option.canMoveBox"
   :fixed-box="option.fixedBox"
   :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="option.fixedNumber"
   :limitMinSize="option.limitMinSize"
   />
  </div>
  <!-- 预览 == 我不需要预览 -->
  <!-- <div class="prive-el">
   <strong>预览:</strong>
   <div class="prive-style" :style="{'width': '200px', 'height': '200px', 'overflow': 'hidden', 'margin': '10px 25px', 'display':'flex', 'align-items' : 'center'}">
   <div class="prive-style" :style="{'width': previews.w + 'px', 'height': previews.h + 'px', 'overflow': 'hidden', 'margin': '10px 25px', 'display':'flex', 'align-items' : 'center'}">
   <div class="preview" :style="previews.div">
    <img :src="/UploadFiles/2021-04-02/previews.url">

3.2 将 el-upload 和 cropper 组合,封装,其他地方可以直接调用

<template>
 <div>
 <!-- 注意:必须关闭自动上传属性 auto-upload -->
 <el-upload
  :http-request="Upload"
  :multiple="true"
  list-type="picture-card"
  :file-list="productImageList"
  :on-remove="removeImage"
  :limit="12"
  :before-upload="beforeAvatarUpload"
  ref="fileUpload"
  :auto-upload="false"
  :on-change="selectChange"
  action=""
  class="cropper-upload-box"
 >
  <i slot="default" class="el-icon-plus"></i>
 </el-upload>
 
 <cropper
  v-if="showCropper"
  :dialog-visible="showCropper"
  :cropper-img="cropperImg"
  :zoomScale="zoomScale"
  @update-cropper="updateCropper"
  @colse-dialog="closeDialog"
  @upload-img="uploadImg"
 />
 </div>
</template>
 
<script>
import Cropper from "@/components/cropper";
import { client, randomWord } from '@/utils/alioss'
export default {
 name: "CropperUpload",
 data() {
 return {
  productImageList: [],
 
  showCropper: false, // 是否显示裁剪框
  cropperImg: "" // 需要裁剪的图片
 };
 },
 props: {
 defaultImgList: {  // 默认显示的图片列表
  type: Array,
  default: () => []
 },
 zoomScale: {   // 裁剪比例,默认1:1
  type: Array,
  default: [1, 1]
 }
 },
 components: {
 Cropper
 },
 watch: {
 defaultImgList: {
  handler: function(newVal, oldVal){
  this.productImageList = newVal // 赋值
  },
  deep: true
 }
 },
 methods: {
 beforeAvatarUpload(file) {
  const isLt2M = file.size / 1024 / 1024 < 2;  // 原图片
  // const isLt2M = this.uploadFile.size / 1024 / 1024 < 1;  //裁剪后的图片(会比原图片大很多,应该是转成Blob的原因导致)
  if (!isLt2M) {
  this.$message.error("上传图片大小不能超过 2MB!");
  this.noCanUpload = true  // 如果这里被拦截,将自动删除不能上传的图片
  return false
  }
  // return isLt2M
 },
 removeImage(file, fileList) {
  const index = this.productImageList.findIndex(item => {
  return item.uid == file.uid;
  });
  if (index > -1) {
  this.productImageList.splice(index, 1);
  }
  this.$emit('getUploadImg', this.productImageList) // 把最新上传的图片列表返回
 },
 Upload(file) {
  var fileName = `img/${randomWord(
  true,
  20
  )}${+new Date()}${file.file.name.substr(file.file.name.indexOf("."))}`;
  // client().put(fileName, file.file).then(result => {
  client()
  .put(fileName, this.uploadFile)
  .then(result => {
   // 上传裁剪后的图片
   console.log(result);
   this.productImageList.push({
   url: result.url,
   uid: file.file.uid,
   saveUrl: "/" + result.name
   });
   this.showCropper = false;
   this.$emit('getUploadImg', this.productImageList) // 把最新上传的图片列表返回
  })
  .catch(err => {
   this.showCropper = false;
   console.log(err);
  });
 },
 
 // 更新图片
 updateCropper() {
  if(!this.noCanUpload){
  let fileList = this.$refs.fileUpload.uploadFiles  // 获取文件列表
  let index02 = fileList.findIndex(item => {  // 把取消裁剪的图片删除
   return item.uid == this.currentFile.uid;
  });
  fileList.splice(index02, 1)
  }
 
  let index = this.$refs.fileUpload.$children.length - 1;
  this.$refs.fileUpload.$children[index].$el.click();
 },
 // 关闭窗口
 closeDialog() {
  this.showCropper = false;
  
  if(!this.noCanUpload){
  let fileList = this.$refs.fileUpload.uploadFiles  // 获取文件列表
  let index = fileList.findIndex(item => {  // 把取消裁剪的图片删除
   return item.uid == this.currentFile.uid;
  });
  fileList.splice(index, 1)
  }
 },
 // 上传图片
 uploadImg(file) {
  this.uploadFile = file;
  // this.$refs.fileUpload.submit();
 
  // 判断裁剪后图片的宽高
  let img = new Image()
  img.src = window.URL.createObjectURL(file);  // Blob转成url 才能给img显示
  img.onload = () => {
  let minProp = Math.min(img.width, img.height) //裁剪后的图片宽,高 ==> 取最小值
  if( minProp < 500){  // 如果最小值比设置的最小值(默认为500)小
   this.$message.error(`请保证图片短边最小为500`);
   return false
  }
  this.$refs.fileUpload.submit();
  }
 },
 selectChange(file) {
  this.noCanUpload = false
  let files = file.raw;
  var reader = new FileReader();
  reader.onload = 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;
  }
  this.cropperImg = data;
 
  // 图片图片尺寸,如果是正方形,则直接上传;否则调用裁剪
  let img = new Image()
  img.src = this.cropperImg;
  img.onload = () => {
   if(img.width == img.height){ // 本来就是正方形 => 直接上传
   this.uploadFile = files;
   this.$refs.fileUpload.submit(); // 调用上传方法
   }else{
   this.showCropper = true;  // 不是正方形的图片才开启裁剪
   this.currentFile = file  // 保存当前操作裁剪的图片
   }
  }
  };
  // 转化为base64
  // reader.readAsDataURL(file)
  // 转化为blob
  reader.readAsArrayBuffer(files);
  
  // this.showCropper = true;  // 默认开启裁剪
 }
 }
};
</script>
 
<style lang="scss">
.cropper-upload-box{
 display: flex;
 .el-upload{
 width: 148px;
 height: 148px;
 }
}
</style>

3.3 其他页面中调用裁剪组件

<!-- 
 zoomScale:定义的裁剪比例;
 defaultImgList: 默认显示的图片列表
 @getUploadImg:这个事件将得到更新后(上传、删除)的图片列表,在页面中重新赋值给默认的列表变量后就可以做页面中的逻辑处理了
 -->
<cropper-upload :zoomScale='[1,1]' :defaultImgList="productImageList" @getUploadImg="getUploadImg"></cropper-upload>

自此,图片裁剪功能实现!!!

3.4 看一下页面中的效果

vue实现图片裁剪后上传

​​​​​​​以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

一句话新闻
微软与英特尔等合作伙伴联合定义“AI PC”:键盘需配有Copilot物理按键
几个月来,英特尔、微软、AMD和其它厂商都在共同推动“AI PC”的想法,朝着更多的AI功能迈进。在近日,英特尔在台北举行的开发者活动中,也宣布了关于AI PC加速计划、新的PC开发者计划和独立硬件供应商计划。
在此次发布会上,英特尔还发布了全新的全新的酷睿Ultra Meteor Lake NUC开发套件,以及联合微软等合作伙伴联合定义“AI PC”的定义标准。