下面是效果图片
下面是源代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>图片上传并裁剪</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
}
.preview-container {
position: relative;
display: inline-block;
border: 1px solid #ccc;
margin-top: 10px;
}
#preview {
max-width: 500px;
max-height: 500px;
display: block;
}
.crop-box {
position: absolute;
border: 2px dashed red;
cursor: move;
background-color: rgba(255, 255, 255, 0.2);
box-sizing: border-box;
}
.resize-handle {
position: absolute;
width: 10px;
height: 10px;
background: red;
z-index: 10;
}
.resize-handle.nw {
top: -5px;
left: -5px;
cursor: nwse-resize;
}
.resize-handle.ne {
top: -5px;
right: -5px;
cursor: nesw-resize;
}
.resize-handle.sw {
bottom: -5px;
left: -5px;
cursor: nesw-resize;
}
.resize-handle.se {
bottom: -5px;
right: -5px;
cursor: nwse-resize;
}
.resize-handle.n {
top: -5px;
left: 50%;
transform: translateX(-50%);
cursor: ns-resize;
}
.resize-handle.s {
bottom: -5px;
left: 50%;
transform: translateX(-50%);
cursor: ns-resize;
}
.resize-handle.e {
right: -5px;
top: 50%;
transform: translateY(-50%);
cursor: ew-resize;
}
.resize-handle.w {
left: -5px;
top: 50%;
transform: translateY(-50%);
cursor: ew-resize;
}
canvas {
margin-top: 20px;
}
</style>
</head>
<body>
<h2>上传图片并裁剪</h2>
<input type="file" id="fileInput" accept="image/*" />
<div class="preview-container" id="container">
<img id="preview" />
<div id="cropBox" class="crop-box" style="width: 100px; height: 100px; top: 50px; left: 50px;">
<div class="resize-handle nw"></div>
<div class="resize-handle ne"></div>
<div class="resize-handle sw"></div>
<div class="resize-handle se"></div>
<div class="resize-handle n"></div>
<div class="resize-handle s"></div>
<div class="resize-handle e"></div>
<div class="resize-handle w"></div>
</div>
</div>
<br />
<button onclick="cropImage()">裁剪图片</button>
<h3>裁剪结果:</h3>
<canvas id="canvas"></canvas>
<script>
const fileInput = document.getElementById('fileInput');
const preview = document.getElementById('preview');
const cropBox = document.getElementById('cropBox');
const container = document.getElementById('container');
let imgLoaded = false;
// 1. 图片上传并显示
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (event) => {
preview.src = event.target.result;
preview.style.display = 'block';
preview.onload = () => {
imgLoaded = true;
// 设置图片最大宽高
let maxW = 500, maxH = 500;
let ratio = Math.min(maxW / preview.naturalWidth, maxH / preview.naturalHeight, 1);
preview.width = preview.naturalWidth * ratio;
preview.height = preview.naturalHeight * ratio;
container.style.width = preview.width + 'px';
container.style.height = preview.height + 'px';
// 裁剪框居中
cropBox.style.left = (preview.width / 2 - cropBox.offsetWidth / 2) + 'px';
cropBox.style.top = (preview.height / 2 - cropBox.offsetHeight / 2) + 'px';
};
};
reader.readAsDataURL(file);
});
// 2. 拖动裁剪框
let isDragging = false;
let dragStartX, dragStartY, boxStartLeft, boxStartTop;
cropBox.addEventListener('mousedown', (e) => {
if (e.target.classList.contains('resize-handle')) return;
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
boxStartLeft = parseInt(cropBox.style.left);
boxStartTop = parseInt(cropBox.style.top);
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
let dx = e.clientX - dragStartX;
let dy = e.clientY - dragStartY;
let newLeft = Math.max(0, Math.min(boxStartLeft + dx, container.offsetWidth - cropBox.offsetWidth));
let newTop = Math.max(0, Math.min(boxStartTop + dy, container.offsetHeight - cropBox.offsetHeight));
cropBox.style.left = newLeft + 'px';
cropBox.style.top = newTop + 'px';
} else if (isResizing) {
// 缩放逻辑见下
const deltaX = e.clientX - resizeStartX;
const deltaY = e.clientY - resizeStartY;
let newWidth = resizeStartWidth;
let newHeight = resizeStartHeight;
let newLeft = resizeStartLeft;
let newTop = resizeStartTop;
switch (resizeDir) {
case 'nw':
newWidth = resizeStartWidth - deltaX;
newHeight = resizeStartHeight - deltaY;
newLeft = resizeStartLeft + deltaX;
newTop = resizeStartTop + deltaY;
break;
case 'ne':
newWidth = resizeStartWidth + deltaX;
newHeight = resizeStartHeight - deltaY;
newTop = resizeStartTop + deltaY;
break;
case 'sw':
newWidth = resizeStartWidth - deltaX;
newHeight = resizeStartHeight + deltaY;
newLeft = resizeStartLeft + deltaX;
break;
case 'se':
newWidth = resizeStartWidth + deltaX;
newHeight = resizeStartHeight + deltaY;
break;
case 'n':
newHeight = resizeStartHeight - deltaY;
newTop = resizeStartTop + deltaY;
break;
case 's':
newHeight = resizeStartHeight + deltaY;
break;
case 'e':
newWidth = resizeStartWidth + deltaX;
break;
case 'w':
newWidth = resizeStartWidth - deltaX;
newLeft = resizeStartLeft + deltaX;
break;
}
// 限制最小尺寸
newWidth = Math.max(20, newWidth);
newHeight = Math.max(20, newHeight);
// 限制在容器内
if (newLeft < 0) newLeft = 0;
if (newTop < 0) newTop = 0;
if (newLeft + newWidth > container.offsetWidth) newWidth = container.offsetWidth - newLeft;
if (newTop + newHeight > container.offsetHeight) newHeight = container.offsetHeight - newTop;
cropBox.style.width = newWidth + 'px';
cropBox.style.height = newHeight + 'px';
cropBox.style.left = newLeft + 'px';
cropBox.style.top = newTop + 'px';
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
isResizing = false;
});
// 3. 缩放裁剪框
let isResizing = false;
let resizeDir = '';
let resizeStartX, resizeStartY, resizeStartWidth, resizeStartHeight, resizeStartLeft, resizeStartTop;
document.querySelectorAll('.resize-handle').forEach(handle => {
handle.addEventListener('mousedown', (e) => {
e.stopPropagation();
isResizing = true;
resizeDir = [...handle.classList].find(cls => cls !== 'resize-handle');
resizeStartX = e.clientX;
resizeStartY = e.clientY;
resizeStartWidth = cropBox.offsetWidth;
resizeStartHeight = cropBox.offsetHeight;
resizeStartLeft = parseInt(cropBox.style.left);
resizeStartTop = parseInt(cropBox.style.top);
e.preventDefault();
});
});
function cropImage() {
if (!imgLoaded) return alert('请先上传图片');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = preview;
const scale = img.naturalWidth / img.width;
const cropX = parseInt(cropBox.style.left) * scale;
const cropY = parseInt(cropBox.style.top) * scale;
const cropW = cropBox.offsetWidth * scale;
const cropH = cropBox.offsetHeight * scale;
canvas.width = cropW;
canvas.height = cropH;
ctx.drawImage(img, cropX, cropY, cropW, cropH, 0, 0, cropW, cropH);
}
</script>
</body>
</html>