Vue中使用vue-croper插件实现图片上传裁剪并传到SpringBoot后台接口

118 篇文章 11 订阅

场景

前后端分离的项目,前端修改头像时,需要对头像进行裁剪并且能实时预览,然后上传到SpringBoot后台。

实现效果如下

 

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

插件官网

https://github.com/xyxiao001/vue-cropper

安装插件

npm install vue-cropper

引用插件

组件内使用
import { VueCropper }  from 'vue-cropper'
components: {
  VueCropper,
},

main.js里面使用
import VueCropper from 'vue-cropper'

Vue.use(VueCropper)

cdn方式使用
<script src="//cdn.jsdelivr.net/npm/vue-cropper@0.4.9/dist/index.js"></script>
Vue.use(window['vue-cropper'].default)
nuxt 使用方式
if(process.browser) {
  vueCropper = require('vue-cropper')
  Vue.use(vueCropper.default)
}

这里只是在头像上传组件内使用,所以采用

import { VueCropper }  from 'vue-cropper'
components: {
  VueCropper,
},

的方式。

使用

把上传图片和裁剪图片和预览都放在一个dialog里面,只有在点击修改头像按钮时才显示此dialog

 

    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened">
      <el-row>
        <el-col :xs="24" :md="12" :style="{height: '350px'}">
          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :fixedBox="options.fixedBox"
            @realTime="realTime"
            v-if="visible"
          />
        </el-col>
        <el-col :xs="24" :md="12" :style="{height: '350px'}">
          <div class="avatar-upload-preview">
            <img :src="previews.url" :style="previews.img" />
          </div>
        </el-col>
      </el-row>
      <br />
      <el-row>
        <el-col :lg="2" :md="2">
          <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
            <el-button size="small">
              上传
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>
          </el-upload>
        </el-col>
        <el-col :lg="{span: 1, offset: 2}" :md="2">
          <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
        </el-col>
        <el-col :lg="{span: 1, offset: 1}" :md="2">
          <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
        </el-col>
        <el-col :lg="{span: 1, offset: 1}" :md="2">
          <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
        </el-col>
        <el-col :lg="{span: 1, offset: 1}" :md="2">
          <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
        </el-col>
        <el-col :lg="{span: 2, offset: 6}" :md="2">
          <el-button type="primary" size="small" @click="uploadImg()">提 交</el-button>
        </el-col>
      </el-row>
    </el-dialog>

这个dialog的布局的效果如下

 

通过:visible.sync="open" 绑定的是否显示的变量为open,需要声明

    data() {
      return {
        // 是否显示弹出层
        open: false,

然后在修改头像按钮的点击事件中

      // 编辑头像
      editCropper() {
        this.open = true;
      },

显示此dialog

然后图片裁剪控件的代码为

          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :fixedBox="options.fixedBox"
            @realTime="realTime"
            v-if="visible"
          />

此控件的属性

 

名称功能默认值可选值
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是否开启截图框宽高固定比例truetrue | 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

这里设置此插件的一些属性与对象options的属性绑定。

声明对象options并设置一些属性

        options: {
          img: 'https://images.cnblogs.com/cnblogs_com/badaoliumangqizhi/1539113/o_qrcode_for_gh_f76a8d7271eb_258.jpg', //裁剪图片的地址
          autoCrop: true, // 是否默认生成截图框
          autoCropWidth: 200, // 默认生成截图框宽度
          autoCropHeight: 200, // 默认生成截图框高度
          fixedBox: true // 固定截图框大小 不允许改变
        },

这里给裁剪的图片设置了一张默认图片,在上传后会重新给该img属性赋值,img就是裁剪图片的地址。

实时预览是通过 @realTime="realTime"

绑定的函数realTime

      // 实时预览
      realTime(data) {
        this.previews = data;
      }

会将参数data赋值给定义的对象preview

previews: {}

然后上面的布局中预览的img是

        <el-col :xs="24" :md="12" :style="{height: '350px'}">
          <div class="avatar-upload-preview">
            <img :src="previews.url" :style="previews.img" />
          </div>
        </el-col>

给img标签赋值参数的url style赋值img属性就可。可以参照其官方案例

@realTime="realTime"
// Real time preview function
realTime(data) {
  var previews = data;
  var h = 0.5;
  var w = 0.2;

  this.previewStyle1 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: h
  };

  this.previewStyle2 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: w
  };

  固定为100宽度
  this.previewStyle3 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: 100 / preview.w
  };

  固定为100高度
  this.previewStyle4 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: 100 / preview.h
  };
  this.previews = data;
},


<div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px',  'overflow': 'hidden',
    'margin': '5px'}">
  <div :style="previews.div">
    <img :src="option.img" :style="previews.img">
  </div>
</div>
<p>中等大小</p>
<div :style="previewStyle1">
  <div :style="previews.div">
    <img :src="previews.url" :style="previews.img">
  </div>
</div>

<p>迷你大小</p>
<div :style="previewStyle2">
  <div :style="previews.div">
    <img :src="previews.url" :style="previews.img">
  </div>
</div>

下方那一排的图片的缩放和旋转都是调用的插件自带的函数

     // 向左旋转
      rotateLeft() {
        this.$refs.cropper.rotateLeft();
      },
      // 向右旋转
      rotateRight() {
        this.$refs.cropper.rotateRight();
      },
      // 图片缩放
      changeScale(num) {
        num = num || 1;
        this.$refs.cropper.changeScale(num);
      },

此插件的其他内置函数

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度
图片加载的回调 imgLoad 返回结果success, error
获取截图信息
this.$refs.cropper.cropW 截图框宽度

this.$refs.cropper.cropH 截图框高度

// 获取截图的base64 数据
this.$refs.cropper.getCropData((data) => {
  // do something
  console.log(data) 
})

// 获取截图的blob数据
this.$refs.cropper.getCropBlob((data) => {
  // do something
  console.log(data) 
})

前端上传图片的实现是使用ElementUI的el-upload实现。

        <el-col :lg="2" :md="2">
          <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
            <el-button size="small">
              上传
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>
          </el-upload>

这里要对其进行一些设置

将其action设置为#不让其上传到远程url,然后重写覆盖其http-request

      // 覆盖默认的上传行为
      requestUpload() {
      },

来覆盖其默认的上传行为。

然后重写其上传前的方法进行上传预处理

      // 上传预处理
      beforeUpload(file) {
        if (file.type.indexOf("image/") == -1) {
          this.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
        } else {
          const reader = new FileReader();
          reader.readAsDataURL(file);
          reader.onload = () => {
            this.options.img = reader.result;
          };
        }
      },

在方法中判断上传文件的类型是否是图片,然后获取图片的url并将其赋值给option的img属性,这样裁剪控件就能获取到上传的图片的url并能显示。

而实时预览也能通过裁剪控件的data的url获取到。

然后就是点击提交按钮裁剪后的照片提交给SpringBoot后台

      // 上传图片
      uploadImg() {
        this.$refs.cropper.getCropBlob(data => {
          let formData = new FormData();
          formData.append("file", data);
          uploadimg(formData).then(response => {
            if (response.code === 200) {
              this.open = false;
              this.options.img = process.env.VUE_APP_BASE_API + response.data;
              console.log(this.options.img)
              this.$emit('changezp', this.options.img)
              this.msgSuccess("修改成功");
            }
            this.visible = false;
          });
        });
      },

通过this.$refs.cropper以及设置的ref="cropper"来获取裁剪控件,然后调用他的内置函数获取blob数据。

然后构建一个FormData对象,并设置其file为裁剪图片的data

然后将此formData采用post请求的方式提交到SpringBoot后台

// 用户头像上传
export function uploadAvatar(data) {
  return request({
    url: '/system/user/profile/avatar',
    method: 'post',
    data: data
  })
}

这里的request是封装的axios请求对象向后台发动post请求并传递data参数。

在SpringBoot后台

    @PostMapping("/upload")
    public AjaxResult uploadProfile(MultipartFile file){
        try {
            String path = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
            path = path.replaceAll("//","/");
            System.out.println("========path: " + path);
            return AjaxResult.success("success",path);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("上传失败");
        }

    }

就能通过MultipartFile file接受到图片文件并上传到服务器返回前端能访问静态资源的路径。

具体实现可以参照下面博客

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108383134

  • 3
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
使用vant-uploadervue-cropper实现裁剪图片并上传,你可以按照以下步骤进行操作: 1. 首先,安装vant和vue-cropper插件。你可以使用npm或yarn来安装它们。 2. 在你的Vue组件,引入vant-uploadervue-cropper组件。 3. 在模板使用vant-uploader组件来实现图片上传功能。设置上传的action属性为你的上传接口地址,并设置on-success事件来处理上传成功后的逻辑。 4. 在on-success事件,获取到上传成功后的图片地址,并将其传递给vue-cropper组件。 5. 在vue-cropper组件,设置裁剪框的样式和裁剪比例等属性。使用v-model指令来绑定裁剪后的图片数据。 6. 在提交按钮的点击事件,将裁剪后的图片数据上传到服务器。 下面是一个简单的示例代码: ```vue <template> <div> <van-uploader action="/upload" :on-success="handleUploadSuccess" ></van-uploader> <vue-cropper v-if="showCropper" :src="cropperSrc" :output-size="{ width: 200, height: 200 }" :output-type="'jpeg'" :fixed-box="true" :fixed-number="\[1, 1\]" v-model="croppedImage" ></vue-cropper> <button @click="handleSubmit">提交</button> </div> </template> <script> import { VanUploader } from 'vant'; import VueCropper from 'vue-cropper'; export default { components: { VanUploader, VueCropper, }, data() { return { showCropper: false, cropperSrc: '', croppedImage: '', }; }, methods: { handleUploadSuccess(response) { // 获取上传成功后的图片地址 const imageUrl = response.data.imageUrl; // 显示裁剪组件 this.showCropper = true; // 设置裁剪组件的图片地址 this.cropperSrc = imageUrl; }, handleSubmit() { // 提交裁剪后的图片数据到服务器 // this.croppedImage 包含裁剪后的图片数据 }, }, }; </script> ``` 请注意,以上代码只是一个简单的示例,你需要根据你的实际需求进行适当的修改和调整。同时,你还需要在后端实现相应的上传和裁剪功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

霸道流氓气质

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

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

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

打赏作者

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

抵扣说明:

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

余额充值