演示
提示
通过鼠标的滚轮来进行图片大小的调整(图片一直是居中的),然后通过移动蓝色的边框来进行图片的裁剪,裁剪的实际效果就是蓝色边框里面的内容
还有就是代码写的比较烂,有一些东西需要你根据你的实际效果来调整
看好浏览器的比例,只能是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>