美化上传按钮
在ejs 页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"></meta>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/form.css'/>
<!-- 本地 Bootstrap 引入方式 -->
<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<script src="/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="./javascripts/image-upload.js"></script>
</head>
<body>
<div class="container">
<h1>文件上传</h1>
<from action="/upload-img" method="post" enctype="multipart/form-data">
<label class="upload-container">
<span class="upload-icon" id="uploadIcon">+</span>
<input accept="image/*" id="avatarInput" type="file" />
<img id="avatarPreview" class="preview-img d-done" />
<button type="button" class="remove-btn" id="removeBtn">x</button>
</label>
<button type="submit" class="btn btn-primary mt-3">提交</button>
</from>
</div>
</body>
</html>
样式
.upload-container{
width: 150px;
height: 150px;
border: 2px solid #ccc;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
overflow: hidden;
background-color: #f8f9fa;
transition:border-color 0.3s;
.upload-icon{
font-size:2rem;
color:#999;
//禁用鼠标事件,该元素变得“不可点击”、“鼠标穿透”
pointer-events: none; //用来控制一个元素是否能响应鼠标事件(点击、悬停、拖动等)
}
.preview-img{
width:100%;
height: 100%;
object-fit: cover;
position: absolute;
top: 0;
left: 0;
}
.remove-btn{
position: absolute;
top:5px;
right:5px;
background-color:rgba(0,0,0,.6);
color:#ffffff;
border:none;
border-radius:50%;
width:24px;
height:24px;
display:none;
align-items: center;
justify-content: center;
cursor:pointer;
font-weight: bold;
}
}
.upload-container:hover{
border-color: #007bff;
}
.upload-container input[type="file"]{
position: absolute;
opacity: 0;
height: 100%;
width: 100%;
cursor: pointer;
}
完成效果
这个效果没有裁剪,进度条、多图片上传
上传进度条
<div class="progress mt-2 d-done" id="progressWrapper">
<div class="progress-bar" role="progressbar" id="uploadProgress" style="width: 0%">0%</div>
</div>
document.getElementById('uploadForm').addEventListener('submit', function(e){
e.preventDefault();
// const blob =preview._blob;
// if(!blob){
// alert("请先选择并裁剪头像");
// return;
// }
const file =input.files[0];
if(!file) return alert('Please upload a valid image!');
let formData = new FormData();
formData.append('file', file);
let xhr = new XMLHttpRequest();
xhr.open('POST', '/upload-avatar');
xhr.upload.addEventListener('progress', (e) => {
if(e.lengthComputable){
let percent = Math.round((e.loaded / e.total) * 100);
progressWrapper.classList.remove('d-none');
progressBar.style.width= percent + '%';
progressBar.innerText = percent + '%';
}
})
xhr.onload =function () {
if(xhr.status === 200) {
alert("successfully uploaded!");
}else{
alert("fail to upload");
}
}
xhr.send(formData);
})
使用cropperjs 裁剪图片
使用npm安装
npm install cropperjs@1.5.13
❗ 关键点:cropperjs@2.x 为模块化版本,不再提供 dist/ 下的浏览器用 JS/CSS 文件
从 v2.0.0 开始,cropperjs 改为 纯 ESM(ES Module)包,它不再包含:
- cropper.js
- cropper.css
- dist/ 文件夹
📌 小提示
版本 | 适合人群 | 是否自带 dist/ |
---|---|---|
1.5.13 | 普通浏览器/EJS 项目 | ✅ 有 JS/CSS,推荐 |
2.x | Vite/Webpack 打包项目 | ❌ 无,需构建 |
引入js、css
<!--本地开发引入 cropper -->
<link rel="stylesheet" href="/cropper/cropper.css">
<script src="/cropper/cropper.js"></script>
弹框
<!-- 裁剪模态框-->
<div class="modal fade modal-mask" id="cropModal" tabindex="1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-fullscreen">
<div class="modal-content p-3">
<div class="modal-body" style="width: 100%; height: 600px;">
<img id="cropImg" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-success" id="cropConfirm">确认裁剪</button>
</div>
</div>
</div>
</div>
js
input.addEventListener('change', (e)=> {
let that=e.target;
let file=that.files[0];
if(file && file.type.startsWith('image/')) {
let reader=new FileReader();
reader.onloadend = (e) => {
//未裁剪前使用的代码
// preview.src = e.target.result;
// preview.classList.remove('d-none');
// removeBtn.style.display = 'flex';
// uploadIcon.style.display = 'none';
//裁剪时的代码
cropImage.src = e.target.result;
new bootstrap.Modal(document.getElementById('cropModal')).show();
cropImage.onload =()=>{
if(cropper) cropper.destroy();
cropper =new Cropper(cropImage,{
aspectRatio: 1,
autoCropArea:1,
viewMode:2
})
}
}
reader.readAsDataURL(file);
}
})