手撸一个vue3的上传图片组件(含裁剪)

先看效果:

这是图片上传按钮。

点击以后跳出以下弹框:

支持裁剪操作,完成后点击上传即可上传裁剪完成后图片。

源代码:

<template>
  <div class="upload-container" onclick="document.getElementById('file-input').click()">
    <button class="upload-button">+</button>
    <input type="file" id="file-input" style="display: none;" accept="image/png, image/jpeg, image/gif, image/jpg" @change="selectImg($event)">
  </div>
<a-modal v-model:open="open">
  <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"
            @realTime="realTime"
            @imgLoad="imgLoad">
        </vue-cropper>
      </div>
      <!--底部操作工具按钮-->
      <div class="footer-btn">
        <div class="scope-btn">
          <a-button style="margin-left: 1%" @click="changeScale(1)">+</a-button>
          <a-button style="margin-left: 1%" @click="changeScale(-1)">-</a-button>
          <a-button style="margin-left: 1%" @click="rotateLeft">↺</a-button>
          <a-button style="margin-left: 1%" @click="rotateRight">↻</a-button>
        </div>
        <div class="upload-btn">
          <a-button type="primary" @click="uploadImg('blob')">上传<i class="el-icon-upload"></i></a-button>
        </div>
      </div>
    </div>
    <!--预览效果图-->
    <div class="show-preview">
      <div :style="previews.div" class="preview">
        <img :src="previews.url" :style="previews.img" alt="h">
      </div>
    </div>
  </div>
</a-modal>
</template>

<script setup>
import {reactive, ref} from "vue";
import { VueCropper } from "vue-cropper";
import axios from "axios";
import {message} from "ant-design-vue";
// 上传路径
const uploadUrl = "https://ip:port/admin/uploadImg";
const open = ref(false);
const option = reactive({
  img: '',             //裁剪图片的地址
  outputSize: 1,       //裁剪生成图片的质量(可选0.1 - 1)
  outputType: 'jpeg',  //裁剪生成图片的格式(jpeg || png || webp)
  info: true,          //图片大小信息
  canScale: true,      //图片是否允许滚轮缩放
  autoCrop: true,      //是否默认生成截图框
  autoCropWidth: 200,  //默认生成截图框宽度
  autoCropHeight: 200, //默认生成截图框高度
  fixed: true,         //是否开启截图框宽高固定比例
  fixedNumber: [1, 1], //截图框的宽高比例
  full: false,         //false按原比例裁切图片,不失真
  fixedBox: true,      //固定截图框大小,不允许改变
  canMove: false,      //上传图片是否可以移动
  canMoveBox: true,    //截图框能否拖动
  original: false,     //上传图片按照原始比例渲染
  centerBox: false,    //截图框是否被限制在图片里面
  height: true,        //是否按照设备的dpr 输出等比例图片
  infoTrue: false,     //true为展示真实输出图片宽高,false展示看到的截图框宽高
  maxImgSize: 3000,    //限制图片最大宽度和高度
  enlarge: 1,          //图片根据截图框输出比例倍数
  mode: '200px 200px'  //图片默认渲染方式
})
const previews=ref({});
//选择图片
function 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)
  open.value=true
}
//实时预览函数
function realTime (data) {
  previews.value = data
}
//初始化函数
function imgLoad (msg) {
  console.log("工具初始化函数====="+msg)
}
const cropper= ref({});
//图片缩放
function changeScale (num) {
  num = num || 1
  cropper.value.changeScale(num)
}
//向左旋转
function rotateLeft () {
  cropper.value.rotateLeft()
}
//向右旋转
function rotateRight () {
  cropper.value.rotateRight()
}

function uploadImg (type) {
  let _this = this;
  if (type === 'blob') {
    //获取截图的blob数据
    cropper.value.getCropBlob(async (data) => {
      let formData = new FormData();
      // 转换回file
      const file = new File([data], "default.jpg");
      formData.append('img',file)
      //调用axios上传
      axios.post(uploadUrl, formData).then(function (res) {
        if(res.status==200){
          message.success("上传成功");
          console.log(res)
        }
      })
    })
  }
}
</script>

<style scoped >
.cropper-content{
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  .cropper-box{
    flex: 1;
    width: 100%;
    .cropper{
      width: auto;
      height: 300px;
    }
  }

  .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: .1s;
    transition: .1s;
    font-weight: 500;
    padding: 8px 15px;
    font-size: 12px;
    border-radius: 3px;
    color: #fff;
    background-color: #409EFF;
    border-color: #409EFF;
    margin-right: 10px;
  }
}
.upload-container {
  width: 100px;
  height: 100px;
  background-color: #c0c0c0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.upload-button {
  font-size: 24px;
  color: #fff;
  background: none;
  border: none;
  outline: none;
  cursor: pointer;
}

.image-preview {
  width: 100%;
  height: 100%;
  background-color: #fff;
  border: 1px solid #ccc;
  display: none;
}
</style>

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值