完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>头像框</title>
<style>
.avatar-frame {
width: 202px;
height: 202px;
margin: auto;
cursor: pointer;
padding: 1px;
border-radius: 5px;
background-color: #f1f1f1;
align-items: center;
}
#select-button {
width: 80px;
height: 40px;
border: 0;
border-radius: 10px;
background-color: #14ad96;
color: #ffffff;
font-weight: bold;
margin: auto auto;
cursor: pointer;
display: block;
}
#select-button:hover {
filter: brightness(0.8);
}
.avatar {
width: 200px;
height: 200px;
margin: 0;
cursor: pointer;
padding: 0;
border-radius: 5px;
border: 4px solid #f1f1f1;
}
#avatar-upload-form {
position: fixed;
top: 120px;
left: 30%;
width: 800px;
height: 700px;
display: flex;
flex-direction: column;
border: 3px solid rgba(0, 0, 0, 0.2);
}
.hidden {
display: none;
}
#avatar-upload-form.hidden {
display: none;
}
.img-box {
margin: 0;
padding: 0;
display: flex;
flex-direction: row;
}
.origin-img-box {
margin: 0;
padding: 0;
width: 600px;
height: 600px;
background-color: #e1e1e1;
}
.resize-box {
margin: 0;
padding: 0;
width: 100px;
height: 100px;
background-color: rgba(0, 0, 0, 0);
border: 3px solid #00bbff;
display: flow;
position: absolute;
}
#resize-box-vertex {
margin: 0;
padding: 0;
width: 5px;
height: 5px;
background-color: rgba(255, 255, 255, 0);
position: absolute;
right: -3px;
bottom: -3px;
cursor: nw-resize;
}
#resize-box-border-bottom {
margin: 0;
padding: 0;
width: 100px;
height: 5px;
background-color: rgba(255, 255, 255, 0);
position: absolute;
left: 0;
bottom: -3px;
cursor: n-resize;
}
#resize-box-border-right {
margin: 0;
padding: 0;
width: 5px;
height: 100px;
background-color: rgba(255, 255, 255, 0);
position: absolute;
right: -3px;
top: 0;
cursor: e-resize;
}
#origin-img {
margin: 0;
padding: 0;
background-color: #ffffff;
}
.cropped-img-box {
margin: 0;
padding: 0;
width: 200px;
height: 600px;
background-color: #ffffff;
}
#cropped-img {
margin: 0;
padding: 30px;
width: 140px;
height: 140px;
background-color: #ffffff;
}
img[src] {
opacity: 1;
}
/*使未加载成功的图片标签隐藏*/
img[src="1"] {
opacity: 0;
transition: opacity 0.5s;
}
.operator {
margin: 0;
padding: 0;
width: 800px;
height: 100px;
background-color: #ffffff;
border-top: 2px solid rgba(0, 0, 0, 0.3);
}
.operator button:hover {
filter: brightness(0.8);
}
.upload-button {
width: 80px;
height: 40px;
border: 0;
border-radius: 10px;
background-color: #14ad96;
color: #ffffff;
font-weight: bold;
margin: 30px 20px 0 80px;
cursor: pointer;
}
.save-button {
width: 80px;
height: 40px;
border: 0;
border-radius: 10px;
background-color: #14ad96;
color: #ffffff;
font-weight: bold;
margin: 30px 20px 0 350px;
cursor: pointer;
}
.cancel-button {
width: 80px;
height: 40px;
border: 0;
border-radius: 10px;
background-color: #14ad96;
color: #ffffff;
font-weight: bold;
margin: 30px 20px 0 20px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="avatar-frame" onclick="showAvatarFrame()">
<img class="avatar" id="avatar" src="1" alt="头像">
</div>
<div>
<button id="select-button" onclick="showAvatarFrame()">
修改头像
</button>
</div>
<div id="avatar-upload-form" class="hidden">
<div class="img-box">
<!--原图片-->
<div class="origin-img-box">
<div class="resize-box" id="resize-box" onmousedown="moveResizeBox(event)">
<!--剪裁框右下角拖动-->
<div id="resize-box-vertex" onmousedown="startResize(event,0)"></div>
<!--剪裁框底边拖动-->
<div id="resize-box-border-bottom" onmousedown="startResize(event,1)"></div>
<!--剪裁框右边拖动-->
<div id="resize-box-border-right" onmousedown="startResize(event,2)"></div>
</div>
<img id="origin-img" src="1"/>
</div>
<!--剪裁后图片-->
<div class="cropped-img-box">
<img id="cropped-img" src="1"/>
</div>
</div>
<div class="operator">
<!--设置上传文件标签隐藏-->
<input type="file" accept=".png,.jpg,.jpeg,.bmp" id="upload" hidden="hidden"/>
<button class="upload-button" onclick="document.getElementById('upload').click()">
上传图片
</button>
<button class="save-button" onclick="saveImage()">
保存
</button>
<button class="cancel-button" onclick="cancelImage()">
取消
</button>
</div>
</div>
<script>
/*图片参数*/
var x = 0;
var y = 0;
var width = 100;
var height = 100;
/*改变大小参数*/
var startX, startY;
/*拖拽参数*/
var moveStartX, moveStartY;
/*图片原始大小*/
var naturalWidth;
var naturalHeight;
/*缩放比例*/
var scale = 1;
var max_X = 600;
var max_Y = 600;
/*拖动剪裁框模式:0从右下角拖动;1从底边拖动;2从右边拖动;*/
var method = 0;
window.onload = function () {
document.getElementById('upload').addEventListener('change', function (e) {
x = 0;
y = 0;
width = 100;
height = 100;
let file = e.target.files[0];
let reader = new FileReader();
reader.onload = function (e) {
let img = new Image();
img.onload = function () {
// 获取图片的原始宽度和高度
naturalWidth = img.naturalWidth;
naturalHeight = img.naturalHeight;
/*设置图片最大显示长宽*/
if (naturalWidth > naturalHeight) {
max_X = 600;
max_Y = naturalHeight / naturalWidth * max_X;
} else {
max_Y = 600;
max_X = naturalWidth / naturalHeight * max_Y;
}
scale = naturalWidth / max_X;
// 显示原始图片
let original_img = document.getElementById('origin-img');
original_img.style.width = max_X + 'px';
original_img.style.height = max_Y + 'px';
original_img.src = e.target.result;
// 创建一个画布用于剪裁
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
canvas.width = width; // 剪裁的宽度
canvas.height = height; // 剪裁的高度
// 根据图片的原始尺寸和剪裁尺寸计算剪裁坐标
let actualCropX = x * scale;
let actualCropY = y * scale;
let actualCropWidth = width * scale;
let actualCropHeight = height * scale;
// 绘制剪裁后的图片
ctx.drawImage(img, actualCropX, actualCropY, actualCropWidth, actualCropHeight, 0, 0, width, height);
// 显示剪裁后的图片
document.getElementById('cropped-img').src = canvas.toDataURL();
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
document.addEventListener('mouseup', () => {
try {
document.removeEventListener('mousemove', resizeImage);
} catch (e) {
}
try {
document.removeEventListener('mousemove', moveBox);
} catch (e) {
}
});
}
function startResize(event, num) {
method = num;
startX = event.clientX;
startY = event.clientY;
document.addEventListener('mousemove', resizeImage);
event.stopPropagation();
}
/*剪裁框拖动改变大小*/
function resizeImage() {
let temp_X = event.clientX;
let temp_Y = event.clientY;
let box = document.getElementById('resize-box');
let borderBottom = document.getElementById('resize-box-border-bottom');
let borderRight = document.getElementById('resize-box-border-right');
/*根据method设置拖动逻辑*/
let enableX = 0;
let enableY = 0;
if (method === 0) {
// 底边右边均可以拖动
enableX = 1;
enableY = 1;
}
if (method === 1) {
// 底边拖动
enableY = 1;
}
if (method === 2) {
// 右边拖动
enableX = 1;
}
/*调整大小*/
width += (temp_X - startX) * enableX;
height += (temp_Y - startY) * enableY;
if (width > height) {
// 水平方向增量大
height = width;
} else {
// 垂直方向增量大
width = height;
}
if (max_X > max_Y) {
if (y + height > max_Y) {
height = max_Y - y;
width = height
}
} else {
if (x + width > max_X) {
width = max_X - x;
height = width;
}
}
if (width < 50) {
width = 50;
height = 50;
}
console.log(width, height);
box.style.width = width + 'px';
box.style.height = height + 'px';
// 调整拖动条大小,给右下角的拖动顶点留5x5的空间
borderBottom.style.width = width - 5 + 'px';
borderRight.style.height = height - 5 + 'px';
handleCropChange();
/*重置开始位置*/
startX = temp_X;
startY = temp_Y;
}
/*开始移动剪裁框*/
function moveResizeBox(event) {
moveStartX = event.clientX;
moveStartY = event.clientY;
document.addEventListener('mousemove', moveBox);
event.stopPropagation();
}
/*移动剪裁框*/
function moveBox() {
let temp_X = event.clientX;
let temp_Y = event.clientY;
let box = document.getElementById('resize-box');
x += temp_X - moveStartX;
y += temp_Y - moveStartY;
/*移动约束*/
if (x + width > max_X) {
x = max_X - width;
}
if (y + height > max_Y) {
y = max_Y - height;
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
console.log(x, y);
box.style.top = y + 'px';
box.style.left = x + 'px';
handleCropChange();
/*重置开始位置*/
moveStartX = temp_X;
moveStartY = temp_Y;
}
/*剪裁重绘*/
function handleCropChange() {
// 获取原始图片的Image对象
let originalImg = document.getElementById('origin-img');
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
// 设置画布的尺寸为剪裁尺寸
canvas.width = width;
canvas.height = height;
// 根据图片的原始尺寸和剪裁尺寸计算剪裁坐标
let actualCropX = x * scale;
let actualCropY = y * scale;
let actualCropWidth = width * scale;
let actualCropHeight = height * scale;
// 绘制剪裁后的图片
ctx.drawImage(originalImg, actualCropX, actualCropY, actualCropWidth, actualCropHeight, 0, 0, width, height);
// 将剪裁后的图片显示在页面上
let croppedImg = document.getElementById('cropped-img');
croppedImg.src = canvas.toDataURL();
}
/*打开头像上传窗口*/
function showAvatarFrame() {
document.getElementById('avatar-upload-form').classList.remove('hidden');
}
function saveImage() {
let avatar = document.getElementById('avatar');
let img = document.getElementById('cropped-img');
avatar.src = img.src;
cancelImage();
}
function cancelImage() {
document.getElementById('avatar-upload-form').classList.add('hidden');
}
</script>
</body>
</html>
效果如下:
头像框
头像上传框
头像上传和剪裁
保存并显示