上传图片实现裁剪功能
下面效果图

下面是源代码
<!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>

浙公网安备 33010602011771号