vue2 结合 elementui 实现图片裁剪上传

1、效果

vue 实现图片裁剪上传

2、准备

第三方库:vue-cropper - npm

npm i vue-cropper

3、封装组件

<template>
  <div class="cropper-wrapper">
    <!-- element 上传图片按钮 -->
    <template v-if="!isPreview">
      <el-upload
        ref="upload"
        class="upload-demo"
        :action="actionUrl"
        drag
        :on-change="handleChangeUpload"
        :auto-upload="false"
        :show-file-list="false"
        :disabled="disabled"
      >
        <i class="el-icon-plus upload-demo-icon"></i>
      </el-upload>
    </template>
    <div v-else class="pre-box">
      <el-upload
        class="upload-demo"
        action=""
        :auto-upload="false"
        :show-file-list="false"
        :on-change="handleChangeUpload"
        :disabled="disabled"
      >
        <img :src="previewImg" alt="裁剪图片" style="width: 100px;height: 100px" />
      </el-upload>
    </div>
    <!-- vueCropper 剪裁图片实现-->
    <el-dialog
      title="图片剪裁"
      :visible.sync="dialogVisible"
      class="crop-dialog"
      append-to-body
    >
      <div class="cropper-content">
        <div class="cropper" style="text-align: center">
          <VueCropper
            ref="cropper"
            :img="option.img"
            :output-size="option.size"
            :output-type="option.outputType"
            :info="true"
            :full="option.full"
            :can-move="option.canMove"
            :can-move-box="option.canMoveBox"
            :original="option.original"
            :auto-crop="option.autoCrop"
            :fixed="option.fixed"
            :fixed-number="option.fixedNumber"
            :center-box="option.centerBox"
            :info-true="option.infoTrue"
            :fixed-box="option.fixedBox"
            :auto-crop-width="option.autoCropWidth"
            :auto-crop-height="option.autoCropHeight"
            @cropMoving="cropMoving"
          />
        </div>
      </div>
      <div class="action-box">
        <el-upload
          class="upload-demo"
          action=""
          :auto-upload="false"
          :show-file-list="false"
          :on-change="handleChangeUpload"
        >
          <el-button type="primary">更换图片</el-button>
        </el-upload>
        <!-- <el-button type="primary" @click="clearImgHandle">
          清除图片
        </el-button> -->
        <el-button type="primary" @click="rotateLeftHandle">
          左旋转
        </el-button>
        <el-button type="primary" @click="rotateRightHandle">
          右旋转
        </el-button>
        <!-- <el-button type="primary" plain @click="changeScaleHandle(1)">
          放大
        </el-button>
        <el-button type="primary" plain @click="changeScaleHandle(-1)">
          缩小
        </el-button> -->
        <el-button type="primary" @click="option.fixed = !option.fixed">
          {{ option.fixed ? '固定比例' : '自由比例' }}
        </el-button>
        <el-button type="primary" @click="downloadHandle('blob')">
          下载
        </el-button>
      </div>
      <div style="height: 30px"></div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" :loading="loading" @click="finish">
          确认
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { VueCropper }  from 'vue-cropper'
import { uploadImage } from '@/api/bff'
export default {
  name: 'Cropper',
  components: {
    VueCropper,
  },
  model: {
    prop: 'value',
    event: 'input'
  },
  props: {
    value: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      actionUrl: process.env.VUE_APP_UPLOAD_API + '/api/v1.0/oss/upload',
      isPreview: false,
      dialogVisible: false,
      previewImg: '', // 预览图片地址
      // 裁剪组件的基础配置option
      option: {
        img: '', // 裁剪图片的地址
        info: true, // 裁剪框的大小信息
        outputSize: 1, // 裁剪生成图片的质量
        outputType: 'png', // 裁剪生成图片的格式
        canScale: true, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        canMoveBox: true, // 截图框能否拖动
        autoCropWidth: 200, // 默认生成截图框宽度
        autoCropHeight: 200, // 默认生成截图框高度
        fixedBox: false, // 固定截图框大小 不允许改变
        fixed: false, // 是否开启截图框宽高固定比例
        fixedNumber: [1, 1], // 截图框的宽高比例
        full: false, // 是否输出原图比例的截图
        original: false, // 上传图片按照原始比例渲染
        centerBox: true, // 截图框是否被限制在图片里面
        infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
      },
      // 防止重复提交
      loading: false,
    };
  },
  watch: {
    value: {
      handler(val, newval) {
        if (val !== newval && val) {
          this.isPreview = true;
          this.previewImg = val
        }
      },
      immediate: true
    }
  },
  methods: {
    // 上传按钮 限制图片大小和类型
    handleChangeUpload(file) {
      const isJPG =
        file.raw.type === 'image/jpeg' || file.raw.type === 'image/png';
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG/PNG 格式!');
        return false;
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
        return false;
      }
      // 上传成功后将图片地址赋值给裁剪框显示图片
      this.$nextTick(async () => {
        // base64方式
        // this.option.img = await fileByBase64(file.raw)
        this.option.img = URL.createObjectURL(file.raw);
        this.loading = false;
        this.dialogVisible = true;
      });
    },
    // 放大/缩小
    changeScaleHandle(num) {
      num = num || 1;
      this.$refs.cropper.changeScale(num);
    },
    // 左旋转
    rotateLeftHandle() {
      this.$refs.cropper.rotateLeft();
    },
    // 右旋转
    rotateRightHandle() {
      this.$refs.cropper.rotateRight();
    },
    // 下载
    downloadHandle(type) {
      let aLink = document.createElement('a');
      aLink.download = 'author-img';
      if (type === 'blob') {
        this.$refs.cropper.getCropBlob((data) => {
          aLink.href = URL.createObjectURL(data);
          aLink.click();
        });
      } else {
        this.$refs.cropper.getCropData((data) => {
          aLink.href = data;
          aLink.click();
        });
      }
    },
    // 清理图片
    clearImgHandle() {
      this.option.img = '';
    },
    // 截图框移动回调函数
    cropMoving() {
      // 截图框的左上角 x,y和右下角坐标x,y
      // let cropAxis = [data.axis.x1, data.axis.y1, data.axis.x2, data.axis.y2]
      // console.log(cropAxis)
    },
    finish() {
      // 获取截图的 blob 数据
      this.$refs.cropper.getCropBlob((blob) => {
        this.loading = true;
        this.dialogVisible = false;
        this.previewImg = URL.createObjectURL(blob);
        this.isPreview = true;
        // this.$refs.submit()
        this.uploadImage(blob)
      });
      // 获取截图的 base64 数据
      // this.$refs.cropper.getCropData(data => {
      //     console.log(data)
      // })
    },
    uploadImage(blob) {
      let file = new File([blob], new Date() + '图片.png', { type: 'image/png', lastModified: Date.now() });
      file.uid = Date.now();
      var fd = new FormData();
      fd.append("file", file, new Date() + "图片.png");
      fd.append("project", "micropark_coordination");

      uploadImage(fd).then(res => {
        console.log('图片上传', res)
        if (res.Type === 200) {
          const imageUrl = res.Data.HostSetting.External + res.Data.PathSetting.Path;
          this.$emit('input', imageUrl);
        }
      });
    }
  },
};
</script>

<style lang="scss" scoped>
:deep(.el-upload-dragger) {
  width: 100px !important;
  height: 100px !important;
}
.cropper-wrapper {
  width: 100%;
  height: 100%;
  .upload-demo .el-upload {
    border: 1px dashed #d9d9d9;
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
  }
  .upload-demo .el-upload:hover {
    border-color: #409eff;
  }
  .upload-demo-icon {
    font-size: 28px;
    color: #8c939d;
    width: 100px;
    height: 100px;
    line-height: 100px;
    text-align: center;
  }
  .pre-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    button {
      width: 100px;
      margin-top: 15px;
    }
  }
}

.crop-dialog {
  .cropper-content {
    padding: 0 40px;

    .cropper {
      width: auto;
      height: 350px;
    }
  }

  .action-box {
    padding: 25px 40px 0 40px;
    display: flex;
    justify-content: center;

    button {
      width: 80px;
      margin-right: 15px;
    }
  }

  .dialog-footer {
    button {
      width: 100px;
    }
  }
}
</style>

4、使用

<upload-picture-cropper v-model="info.UserExternalIdentify.WeChatQrCode" :disabled="isDisable" />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/581145.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UDP和TCP(传输层)

这里写目录标题 UDPUDP的基本特点UDP协议报文格式 TCPTCP协议报文格式TCP特点可靠传输实现机制确认应答超时重传数据丢了应答报文丢了 小结 UDP UDP的基本特点 无连接不可靠传输面向数据报全双工 UDP协议报文格式 2个字节有效范围(无符号): 0 ~ 65535(2^16 - 1). 2个字节有效范…

用数据检验函数正确性,matlab2C

数据存取格式 filename1 g.txt; fid1 fopen(filename1,w); for i 1 : length(g)for j1:size(g,2)if(j1)fprintf(fid1,{%.16f,,g(i,j)); elseif(j>1&&j<151)fprintf(fid1,%.16f,,g(i,j)); elsefprintf(fid1,%.16f},\n,g(i,j));endend%fprintf(fid1,\n…

如何用Python语言实现远程控制4路控制器/断路器

如何用Python语言实现远程控制4路控制器/断路器呢&#xff1f; 本文描述了使用Python语言调用HTTP接口&#xff0c;实现控制4路控制器/断路器&#xff0c;支持4路输出&#xff0c;均可独立控制&#xff0c;可接入各种电器。 可选用产品&#xff1a;可根据实际场景需求&#xf…

Spring Web MVC入门(3)——响应

目录 一、返回静态页面 RestController 和 Controller之间的关联和区别 二、返回数据ResponseBody ResponseBody作用在类和方法的情况 三、返回HTML代码片段 响应中的Content-Type常见的取值&#xff1a; 四、返回JSON 五、设置状态码 六、设置Header 1、设置Content…

2024李卜常识开天斧

2024年&#xff0c;李卜常识开天斧课程以其独特的魅力吸引了众多学子。这门课程如同开天辟地的神斧&#xff0c;帮助我们打开常识知识的大门&#xff0c;引领我们走进一个全新的学习世界。在李卜老师的悉心指导下&#xff0c;我们逐渐掌握了各种常识知识&#xff0c;拓宽了视野…

leaftjs+turfjs+idw纯前端实现等值面绘图+九段线

最近有个绘制等值面图的需求。我们一般的实现路径是&#xff1a; 1.后台绘图&#xff0c;用surfer绘制好&#xff0c;给前端调用叠加到地图。 2.后台用python绘图&#xff0c;绘制好给前端调用&#xff0c;叠加到地图。 3.后台进行插值计算、地图裁剪、最终生成geojson文件或…

VS2019配合QT5.9开发IRayAT430相机SDK

环境配置 VS2019 QT5.9 编译器版本 MSVC2017_64添加系统环境变量&#xff08;完毕后重启电脑&#xff09; 从VS2019中下载Qt插件 从VS2019中添加单个编译组件 上述操作完成后用VS打开工程文件&#xff0c;工程文件地址 &#xff1a; C:\Users\86173\Desktop\IRCNETSDK_W…

初识 Linux

一、基础命令 0、 ls cd cat pwd 当前工作目录 find -name 测试.py 查找文件 grep "学院" 测试.py 查找字符串 "学院" 在文件 测试.py 中位置&#xff0c;输出所在的 行 1、重定向器 echo "Hello Kali Linux!" > Hello 创建 文件 Hel…

openssl3.2 - exp - 使用默认的函数宏,在release版中也会引入__FILE__

文章目录 openssl3.2 - exp - 使用默认的函数宏&#xff0c;在release版中也会引入__FILE__概述笔记验证是否__FILE__在release版下也能用&#xff1f;将openssl编译成release版的&#xff0c;看看CRYPTO_free()是否只需要一个参数就行&#xff1f;将工程中的openssl相关的库换…

stream中的foreach,allMatch,noneMatch,anyMatch的基本使用

1.1foreach遍历集合元素 1.2anyMatch()的使用 结论:上边使用foreach循环遍历和使用anyMatch()的作用相同 2.allMatch() 2.1初级使用 2.2进级使用 3.noneMatch()使用

Python 实现视频去抖动技术

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 视频去抖动是视频处理中的一项重要技术&#xff0c;它可以有效地减少视频中由于相机震动或手…

华为matebook 14安装ubuntu双系统

一、准备u盘 首先格式化u盘(选择FAT32) 二、确认电脑类型 键盘按下win+r(win:开始键/也就是Windows的标志那个键),在输入框内输入msinfo32后,回车确认 确定自己电脑 硬盘 的类型: 在显示屏下方的搜索框内搜索“计算机管理” 点击进入后,再点击左边列表内的“磁…

拉普拉斯IPO:荣获国家级专精特新和国家级制造业单项冠军殊荣

近期&#xff0c;拉普拉斯荣获国家级专精特新和国家级制造业单项冠军的殊荣&#xff0c;这无疑是对其在技术和发展方面的肯定。这些荣誉证明了拉普拉斯在光伏行业的卓越表现和持续创新&#xff0c;以及其在国内制造业中的领先地位&#xff0c;进一步彰显了拉普拉斯在技术研发和…

智慧浪潮下的产业园区:洞察智慧化转型如何打造高效、绿色、安全的新园区

目录 一、引言 二、智慧化转型的内涵与价值 三、打造高效园区的智慧化策略 1、建设智能化基础设施 2、推广智能化应用 3、构建智慧化服务平台 四、实现绿色园区的智慧化途径 1、推动绿色能源应用 2、实施绿色建筑设计 3、加强环境监测与治理 五、保障园区安全的智慧…

【办公类-22-14】周计划系列(5-6)“周计划-06 19周的周计划教案合并打印PDF(最终打印版))

背景需求&#xff1a; 花了十周&#xff0c;终于把周计划教案的文字都写满、加粗、节日替换了。为了便于打印&#xff0c;我把19周的周计划教案全部合并在一起PDF。制作打印用PDF 思路 1、周计划是单独打印一张&#xff0c;因此要在第2页插入空白页&#xff0c; 2、教案有3页…

[计算机效率] 截图工具:FastStone Capture

3.19 截图工具&#xff1a;FastStone Capture FastStone Capture是一款功能强大的屏幕捕捉软件&#xff0c;体积小巧、功能强大&#xff0c;不但具有常规截图等功能&#xff0c;更有从扫描器获取图像&#xff0c;和将图像转换为PDF文档等功能。 截屏功能&#xff1a;支持全屏截…

【Python数据库】MongoDB

文章目录 [toc]数据插入数据查询数据更新数据删除 个人主页&#xff1a;丷从心 系列专栏&#xff1a;Python数据库 学习指南&#xff1a;Python学习指南 数据插入 from pymongo import MongoClientdef insert_data():mongo_client MongoClient(hostlocalhost, port27017)co…

Git变更账户、查看账户

1、变更账户 &#xff08;1&#xff09;修改当前文件夹用户 git config user.name “新用户名” git config user.email “新邮箱” &#xff08;2&#xff09;修改全局git用户 git config - -global user.name “新用户名” git config - -global user.email “新邮箱”…

计算机网络——初识网络

一、局域网与广域网 1.局域网&#xff08;LAN&#xff09; 局域网&#xff1a;即Local Area Network&#xff0c;简称LAN。Local即标识了局域⽹是本地&#xff0c;局部组建的⼀种私有⽹络。局域⽹内的主机之间能⽅便的进⾏⽹络通信&#xff0c;⼜称为内⽹&#xff1b;局域⽹和…

【c++】----STL简介string

目录 1. 什么是STL 2. STL的版本 3. STL的六大组件 4.STL的缺陷 5.string类 1. 为什么学习string类&#xff1f; 6.string类的常用接口说明&#xff08;下面我们只讲解最常用的接口&#xff09; 1.string 常见构造 2.string类的遍历 iterator 迭代器遍历 &#xff08;…
最新文章