当前位置: 首页 > news >正文

node.js 实战——在express 中将input file 美化,并完成裁剪、上传进度条

美化上传按钮

在这里插入图片描述

在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.xVite/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);}})

在这里插入图片描述

相关文章:

  • uni-pages-hot-modules插件:uni-app的pages.json的模块化及模块热重载
  • python实现的音乐播放器
  • 【Pandas】pandas DataFrame abs
  • 无实体对话式社交机器人 拟人化印象形成机制:基于多模态交互与文化适配的拓展研究
  • 使用ESPHome烧录固件到ESP32-C3并接入HomeAssistant
  • 使用pytorch保存和加载预训练的模型方法
  • 基于Transformer的多资产收益预测模型实战(附PyTorch实现与避坑指南)
  • OpenHarmony平台驱动开发(九),MIPI DSI
  • 如何使用npm下载指定版本的cli工具
  • 【MySQL】存储引擎 - MyISAM详解
  • FPGA_Verilog实现QSPI驱动,完成FLASH程序固化
  • [ctfshow web入门] web57
  • 到达最后一个房间的最少时间II 类似棋盘转移规律查找
  • QTDesinger如何给label加边框
  • Java后端程序员学习前端之JavaScript
  • k8s的pod挂载共享内存
  • Mysql-OCP PPT课程讲解并翻译
  • 数据结构 - 9( 位图 布隆过滤器 并查集 LRUCache 6000 字详解 )
  • 9. 从《蜀道难》学CSS基础:三种选择器的实战解析
  • 分贝计在评估噪音对学习的影响中起着至关重要作用
  • 我驻苏丹使馆建议在苏中国公民尽快撤离
  • 陈雯出任外交部离退休干部局局长,此前为外交部办公厅副主任
  • 象屿集团:对去化压力大、市场有效需求不足区域坚决暂停投资,打造多元上市路径
  • 广西科学调度保障春灌面积1373.53万亩
  • 制定出台民营经济促进法有何重大意义?全国人大常委会法工委回应
  • 厚重与潮流交织,淮安展现“运河之都”全新城市想象