前端裁剪图片

 演示

提示

通过鼠标的滚轮来进行图片大小的调整(图片一直是居中的),然后通过移动蓝色的边框来进行图片的裁剪,裁剪的实际效果就是蓝色边框里面的内容

还有就是代码写的比较烂,有一些东西需要你根据你的实际效果来调整
看好浏览器的比例,只能是100%,超出或者缩小都有问题

代码

<script setup name="CustomUploadsize">
import { reactive, defineProps, ref, watch, defineEmits } from "vue";
import { debounce } from "lodash-es";

const emit = defineEmits(["update:dialogVisible", "submitSuccess"]);
const _this = reactive({
  dialogVisible: false,
  loading: false,
  loadingTwo: false,
  style: {
    width: 280,
    height: 280,
  },
  imgSrc: "",
  judgeMove: false,
  offsetX: 0,
  offsetY: 0,
  img1: "",
  img2: "",
});

function close() {
  _this.dialogVisible = false;
  emit("update:dialogVisible", false);
}

const imgUpload = ref(null);
const customRef = ref(null);
// 图片上传
const handleChange = () => {
  imgUpload.value.click();
};
// 上传的方法
function upload(event) {
  _this.loading = true;
  getImgBase64(event.target.files[0])
    .then((res) => {
      _this.imgSrc = res;
    })
    .finally(() => {
      event.target.value = "";
      _this.loading = false;
    });
}
// 图片转base64(这里换成你图片上传的方法)
// drwaImage 如果你传入线上的图片地址,可能会出现一些问题,这边推荐使用base64的,
// 等裁剪完成的时候,你再使用你的图片上传的方法
function getImgBase64(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = function (event) {
      resolve(event.target.result);
    };
    reader.readAsDataURL(file);
  });
}

// 监听content元素 滚轮事件
const mousewheel = debounce((e) => {
  let imgWidth =
    customRef.value.offsetWidth ||
    customRef.value.width ||
    customRef.value.clientWidth;
  let imgHeight =
    customRef.value.offsetHeight ||
    customRef.value.height ||
    customRef.value.clientHeight;
  if (e.deltaY > 0) {
    _this.style.width = getNumber(imgWidth - 10);
    _this.style.height = getNumber(imgHeight - 10);
  } else {
    _this.style.width = imgWidth + 10;
    _this.style.height = imgHeight + 10;
  }
}, 100);
function getNumber(val) {
  return val < 0 ? 0 : val;
}
let contentRef = ref(null);
let moveItemRef = ref(null);

function mousedown(e) {
  if (e.which === 1) {
    _this.judgeMove = true;
    _this.offsetX = e.clientX - moveItemRef.value.getBoundingClientRect().left;
    _this.offsetY = e.clientY - moveItemRef.value.getBoundingClientRect().top;
  }
}
function mouseup() {
  _this.judgeMove = false;
}
function mouseout() {
  _this.judgeMove = false;
}
function mousemove(e) {
  if (_this.judgeMove) {
    const x =
      e.clientX - _this.offsetX - contentRef.value.getBoundingClientRect().left;
    const y =
      e.clientY - _this.offsetY - contentRef.value.getBoundingClientRect().top;
    moveItemRef.value.style.left = x + "px";
    moveItemRef.value.style.top = y + "px";
  }
}

// 保存
function saveSubmit() {
  if (_this.imgSrc === "") {
    // return ElMessage.error("请上传图片");
    console.log("请上传图片");
    return;
  }
  try {
    _this.loadingTwo = true;
    CroppingImage((e) => {
      console.log(e);
    });
  } catch (err) {
    _this.loadingTwo = false;
  }
}
// 裁剪图片
function CroppingImage(callback) {
  let img = new Image(_this.style.width, _this.style.height);
  img.src = _this.imgSrc;
  img.onload = function () {
    let canvas = document.createElement("canvas");
    canvas.width = 490; // 这里的宽度是就是 class="content" 的宽度
    canvas.height = 280; // 这里的高度就是 class="content" 的高度
    let arr = getOverlap();
    let ctx = canvas.getContext("2d");
    //  这里490 - img.width /2 是让图片居中,因为裁剪的坐标就是根据图片的居中来设置的
    // drwaImage 如果你传入线上的图片地址,可能会出现一些问题,这边推荐使用base64的
    ctx.drawImage(img, (490 - img.width) / 2, 0, img.width, img.height);
    let imageData = ctx.getImageData(...arr);
    const newCanvas = document.createElement("canvas");
    newCanvas.width = imageData.width;
    newCanvas.height = imageData.height;
    const newContext = newCanvas.getContext("2d");
    newContext.putImageData(imageData, 0, 0);
    newCanvas.toBlob(function (blob) {
      // 裁剪完成,上传图片
      getImgBase64(blob).then((res) => {
        console.log(res);
        callback(res);
        _this.loadingTwo = false;
      });
    });
  };
}

// 获取重叠的坐标
function getOverlap() {
  const rect1 = contentRef.value.getBoundingClientRect();
  const rect2 = moveItemRef.value.getBoundingClientRect();
  // 计算重叠区域
  const overlap = {
    left: Math.max(rect1.left, rect2.left),
    right: Math.min(rect1.right, rect2.right),
    top: Math.max(rect1.top, rect2.top),
    bottom: Math.min(rect1.bottom, rect2.bottom),
  };

  // 重叠的宽度
  var overlapWidth = overlap.right - overlap.left;
  // 重叠的高度
  var overlapHeight = overlap.bottom - overlap.top;
  return [
    overlap.left - rect1.left,
    overlap.top - rect1.top,
    overlapWidth,
    overlapHeight,
  ];
}
</script>

<template>
  <div>
    <input
      ref="imgUpload"
      v-show="false"
      @change="upload"
      type="file"
      name="file"
      accept="image/*"
      class="file-input"
    />
    <div
      ref="contentRef"
      class="content"
      @dragstart.prevent
      @mousewheel.prevent="mousewheel"
    >
      <div
        ref="customRef"
        class="custom-ref"
        :style="{
          width: _this.style.width + 'px',
          height: _this.style.height + 'px',
        }"
      >
        <img :src="_this.imgSrc" alt="" class="img-100" />
      </div>
      <div
        ref="moveItemRef"
        class="move-item"
        @mousedown="mousedown"
        @mouseup="mouseup"
        @mouseout="mouseout"
        @mousemove="mousemove"
      ></div>
    </div>
  </div>
  <span class="dialog-footer">
    <el-button
      type="primary"
      @click="handleChange"
      :loading="_this.loading"
      class="btn upload-new"
    >
      上传图片
    </el-button>
    <el-button
      @click="saveSubmit"
      type="primary"
      class="btn save"
      :loading="_this.loadingTwo"
    >
      保存
    </el-button>
    <el-button type="primary" @click="close" class="btn cancel">取消</el-button>
  </span>
</template>

<style lang="scss" scoped>
.content {
  position: relative;
  width: 490px;
  height: 280px;
  background: #d8d8d8;
  margin-bottom: 9px;
  user-select: none;
  overflow: hidden;
  margin: 0 auto 9px;
  .custom-ref {
    margin: 0 auto;
    // border-radius: 50%;
    overflow: hidden;
    .img-100 {
      width: 100%;
      height: 100%;
    }
  }
  .move-item {
    position: absolute;
    top: 40px;
    left: 145px;
    width: 200px;
    height: 200px;
    border: 2px solid #409eff;
    background-color: transparent;
    &:hover {
      cursor: move;
    }
  }
}

.dialog-footer {
  display: flex;
  justify-content: center;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是大刚啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值