原生js极简文件选择器,文件数量大小类型限制,元素自动渲染,自动获取formData提交至后端 您所在的位置:网站首页 文件上传后端代码 原生js极简文件选择器,文件数量大小类型限制,元素自动渲染,自动获取formData提交至后端

原生js极简文件选择器,文件数量大小类型限制,元素自动渲染,自动获取formData提交至后端

2023-06-15 01:13| 来源: 网络整理| 查看: 265

以前对文件处理一直很抵触,因为练习成本较高,原生的文件选择器了解不多,所以最近补了补课,然后自己手搓了一个文件选择器,先看看效果。

 基础样式就是这样子,然后直接把文件拖入或者点击选择文件就行

图片文件支持预览,可以删除已选中文件,文件上传可以限制数量

引用的方法如下

new FileUploader({ id: "FileUploader", limit: 10, fileSize: [{ type: "*", size: "10MB", }], url: "http://localhost:7385/fileUpload" }, this)

 new一个对象就行,id绑定一个div,然后样式会自动注入,

limit是限制上传数量,

fileSize数组里插入文件限制的大小,“ * ”是全部,支持对单种文件类型限制大小,输入Mb、B、kb、Gb,或者数字都行,自动转成字节大小,比如:

new FileUploader({ id: "FileUploader", limit: 10, fileSize: [{ type: "png", size: "500KB", }, { type: "JGP", size: "151515", }, { type: "docx", size: "1Mb", }], url: "http://localhost:7385/fileUpload" }, this)

url是提交到的接口,使用内置的方法会发送一个formdata,用List接收使用方法如下:

let fileUpload=new FileUploader({ id: "FileUploader", limit: 10, fileSize: [{ type: "*", size: "10MB", }], url: "http://localhost:7385/fileUpload" }, this) //运行这一句就行 fileUpload.submit()

但是不同的项目需求可能不太一样,所以还是推荐直接获取formData然后自己上传,方法如下:

let fileUploader=new FileUploader({ id: "FileUploader", limit: 10, fileSize: [{ type: "*", size: "10MB", }], url: "http://localhost:7385/fileUpload" }, this) var formData=fileUploader.getFormData()

这玩意写了几个小时,考虑的东西还不太全面,代码样式比较难改,因为我想把玩意封装到一个js里,所以css也是js注入,具体代码如下,自取:

class FileUploader { constructor(setting, vue) { this.setting = setting this.Vue = vue this.fileSizeLimit = null if (this.setting.fileSize != null) { this.fileSizeLimit = new Map(); for (var a = 0; a < this.setting.fileSize.length; a++) { //console.log(this.setting.fileSize[a]) this.fileSizeLimit.set(this.setting.fileSize[a].type, this.convertToBytes(this.setting.fileSize[a] .size)) } } //console.log(this.fileSizeLimit) this.styleNum = 0 this.fileList = [] this.fileUpload = document.getElementById(this.setting.id) console.log(this.Vue) this.fileUpload.classList.add("FILEUPLOADERfileBaseUploaderBlock") this.styleElement = document.createElement('style'); document.head.appendChild(this.styleElement); this.styleSheet = this.styleElement.sheet; this.addCss() this.init() this.inputDisable() this.fileListEle = this.dc("div", "FILEUPLOADERfileListEle") this.fileUpload.append(this.fileListEle) } convertToBytes(size) { const units = { B: 1, KB: 1024, MB: 1024 * 1024, GB: 1024 * 1024 * 1024, TB: 1024 * 1024 * 1024 * 1024, }; const regex = /^(\d+(\.\d+)?)\s*([BKMGT]B?)$/i; const matches = size.match(regex); if (matches) { const value = parseFloat(matches[1]); const unit = matches[3].toUpperCase(); if (units.hasOwnProperty(unit)) { return value * units[unit]; } } else if (!isNaN(size)) { // 输入的是纯数字,直接返回大小 return parseFloat(size); } return NaN; } getFormData() { const formData = new FormData(); // 将文件数组添加到 FormData 中 for (let i = 0; i < this.fileList.length; i++) { formData.append('files', this.fileList[i]); } return formData } async submit() { if (this.fileList.length == 0) { this.message("未选择文件") return } // 创建一个 FormData 对象 const formData = new FormData(); // 将文件数组添加到 FormData 中 for (let i = 0; i < this.fileList.length; i++) { formData.append('files', this.fileList[i]); } const { data: result } = await this.Vue.$http.post(this.setting.url, formData) this.message("上传成功") if (result.code == 200) { this.fileListEle.innerHTML = '' this.fileList = [] return result } else { return result } // 发起 POST 请求到后端接口 // fetch('http://123.56.27.115:7385/fileUpload', { // method: 'POST', // body: formData, // }) // .then(response => { // //console.log(response) // }) // .catch(error => { // //console.error('请求错误:', error); // }); } message(msg) { var Msg = this.dc("div", "FILEUPLOADERmessage").text(msg) document.body.appendChild(Msg) var op = 0 var top = 0 var emo = self.setInterval(() => { op += 0.1 Msg.style.opacity = op; top = top + (1.5 - (top / 7 * top / 7)); //console.log((1.5 - (top / 7 * top / 7))) Msg.style.top = top + "%"; //console.log(top) }, 17) setTimeout(() => { self.clearInterval(emo) }, 250) setTimeout(() => { document.body.removeChild(Msg) }, 2000) } viewFileList() { if (this.fileList[this.fileList.length - 1].type.substr(0, 5) == "image") { const reader = new FileReader(); reader.readAsDataURL(this.fileList[this.fileList.length - 1]); //console.log(this.fileList[this.fileList.length - 1]) reader.onload = (event) => { const img = new Image(); img.src = event.target.result; img.onload = () => { let delIcon = this.dc("div", "FILEUPLOADERdelIcon") let index = this.fileList.length - 1 const fileViewBlock = this.dc("div", "FILEUPLOADERfileViewBlock") const canvas = this.dc("canvas", "FILEUPLOADERviewCanvas"); fileViewBlock.append(delIcon).append(this.dc("div", "FILEUPLOADERviewCanvasBlock") .append(canvas)) .append(this.dc( "div", "FILEUPLOADERfileNameImg").text(this.fileList[this.fileList.length - 1].name) .tit( this.fileList[this.fileList.length - 1].name)) this.fileListEle.append(fileViewBlock) delIcon.onclick = () => { this.fileList.splice(index, 1) this.fileListEle.removeChild(fileViewBlock) this.inputAble() //console.log(this.fileList) } const ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); const width = img.width; const height = img.height; ctx.drawImage(img, 0, 0, canvas.width, canvas.height); }; img.onerror = (error) => { reject(error); }; }; } else { let index = this.fileList.length - 1 let delIcon = this.dc("div", "FILEUPLOADERdelIcon") const fileViewBlock = this.dc("div", "FILEUPLOADERfileViewBlock").append(delIcon).append(this.dc("div", "FILEUPLOADERfile-icon").append(this .dc("div", "FILEUPLOADERfileName").text(this.fileList[this.fileList.length - 1].name).tit( this .fileList[this.fileList.length - 1].name))) this.fileListEle.append(fileViewBlock) delIcon.onclick = () => { this.fileList.splice(index, 1) this.fileListEle.removeChild(fileViewBlock) this.inputAble() //console.log(this.fileList) } } } init() { this.fileUpload.classList.add("FILEUPLOADERuploadInput") this.fileInputBlock = this.dc("div", "FILEUPLOADERinputBlock") this.fileInput = this.dc("input", "FILEUPLOADERInput") this.fileInput.type = "file" this.fileInput.addEventListener('change', (event) => { if (this.fileInput.disabled) { this.message("已达到限制上传数量") return } for (var a = 0; a < this.fileList.length; a++) { if (this.fileList[a].name == event.target.files[0].name && this.fileList[a].lastModified == event .target.files[0].lastModified && this.fileList[a].size == event.target.files[0].size) { this.message("请勿重复上传文件") return } } var fileType = event.target.files[0].name.split(".") var fileType = fileType[fileType.length - 1]; if (this.fileSizeLimit.has("*")) { if (this.fileSizeLimit.get("*") < event.target.files[0].size) { this.message("超过限制大小(" + this.formatBytes(this.fileSizeLimit.get("*")) + ")") return } } else if (this.fileSizeLimit.has(fileType)) { if (this.fileSizeLimit.get(fileType) < event.target.files[0].size) { this.message("超过限制大小(" + this.formatBytes(this.fileSizeLimit.get(fileType)) + ")") return } } this.fileList.push(event.target.files[0]) this.fileNumEle.text(this.setting.limit + "/" + this.fileList.length) this.inputDisable() //console.log(this.fileList) this.viewFileList() }); this.signFont = this.dc("font", "FILEUPLOADERaddFont").text("点击/拖拽选择") this.addIcon = this.dc("font", "FILEUPLOADERaddIcon").text("+") this.fileNumEle = this.dc("div", "FILEUPLOADERfileNum").text(this.setting.limit + "/0") this.fileInputBlock.append(this.fileInput).append(this.dc("div", "FILEUPLOADERinputIcon").append(this .addIcon).append(this.signFont)) this.fileUpload.append(this.fileInputBlock) this.fileUpload.append(this.fileNumEle) this.fileInputBlock.addEventListener('mouseover', (event) => { this.fileInputBlock.style.opacity = "0.6" }); this.fileInputBlock.addEventListener('mouseout', (event) => { this.fileInputBlock.style.opacity = "1" }); this.fileInputBlock.addEventListener('dragover', (event) => { this.fileInputBlock.style.opacity = "0.6" }); this.fileInputBlock.addEventListener('dragleave', (event) => { this.fileInputBlock.style.opacity = "1" }); this.fileInputBlock.addEventListener('drop', (event) => { this.fileInputBlock.style.opacity = "1" }); this.fileInputBlock.addEventListener('change', (event) => { this.fileInputBlock.style.opacity = "1" }); } formatBytes(bytes) { if (bytes === 0) { return '0 B'; } const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); const size = parseFloat((bytes / Math.pow(k, i)).toFixed(2)); return size + ' ' + sizes[i]; } inputDisable() { if (this.fileList.length == this.setting.limit) { this.fileInput.disabled = true; this.fileInputBlock.style.border = "2px solid #9e9e9e" this.signFont.style.color = "#9e9e9e" this.addIcon.style.color = "#9e9e9e" } } inputAble() { //console.log(this.fileList.length + "," + this.setting.limit) if (this.fileList.length != this.setting.limit) { this.fileInput.disabled = false; this.fileInputBlock.style.border = "2px solid #599cff" this.signFont.style.color = "#599cff" this.addIcon.style.color = "#599cff" } } addCss() { // this.style(`.message{width:20%;padding:15px;margin-left:40%;}`) this.style(`.FILEUPLOADERfileViewBlock{width:75px;height:95px;float:left;margin:5px;overflow:hidden;}`) this.style(`.FILEUPLOADERfileBaseUploaderBlock { display: flex; width:98%; flex-direction: column; float: left; padding:1%; background-color:#fff; }`) this.style(`.FILEUPLOADERuploadInput{padding:10px;display:flex;flex-direction:column;width:100%}`) this.style( `.FILEUPLOADERInput{height:100%;width:100%; margin-top:-0px; float:left;background-color:red;opacity: 0;cursor: pointer;}` ) this.style(`.FILEUPLOADERfileNum{float:left;margin-top:-30px;margin-left:115px}`) this.style( `.FILEUPLOADERfileName{background-color:#f8f8f8;width:71px;padding-left:2px;padding-right:2px; height:25px;text-align:center;line-height:20px;float:left;font-size: 12px;white-space: nowrap;overflow:hidden;margin-top:75px;}` ) this.style( `.FILEUPLOADERfileNameImg{background-color:#f8f8f8;width:71px;padding-left:2px;padding-right:2px; height:25px;text-align:center;line-height:20px;float:left;font-size: 12px;white-space: nowrap;overflow:hidden;}` ) this.style( `.FILEUPLOADERviewCanvasBlock{width:75px;height:75px;overflow:hidden;float:left;background-color:#f8f8f8;}` ) this.style(`.FILEUPLOADERviewCanvas{width:75px; position: relative; z-index: 1;}`) this.style( `.FILEUPLOADERinputBlock{width:100px;height:100px;float:left;border:2px solid #33a0ff;border-radius:3px;cursor: pointer;}` ) this.style( `.FILEUPLOADERinputIcon {width: 100% ;height: 100% ;float: left;margin-top: -100% ;color: #599cff;}` ) this.style(`.FILEUPLOADERfile-icon {background-color:#f8f8f8;float:left; width: 75px; height: 75px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024' width='75' height='75'%3E%3Cpath d='M506.88 257.024H321.024c-25.6 0-46.08 20.992-46.08 46.592v371.2c0 25.6 20.48 46.592 46.08 46.592h279.04c25.6 0 46.592-20.992 46.592-46.592V396.288L506.88 257.024z m46.08 371.2H367.616v-46.592H552.96v46.592z m0-92.672H367.616v-46.592H552.96v46.592zM483.328 419.328V291.84l127.488 127.488H483.328z' fill='%23AAD4FF'/%3E%3Cpath d='M599.552 314.88H413.696c-25.6 0-46.08 20.992-46.08 46.592v371.2c0 25.6 20.48 46.592 46.08 46.592h279.04c25.6 0 46.592-20.992 46.592-46.592V454.144l-139.776-139.264z m46.592 371.2H460.288v-46.08h185.856v46.08z m0-92.672H460.288v-46.592h185.856v46.592z m-69.632-116.224V349.696l127.488 127.488h-127.488z' fill='%232B95FF'/%3E%3Cpath d='M827.904 233.472H798.72v-29.696c0-6.656-5.12-11.776-11.776-11.776-6.656 0-11.776 5.12-11.776 11.776v29.696h-29.696c-6.656 0-11.776 5.12-11.776 11.776s5.12 11.776 11.776 11.776h29.696V286.72c0 6.656 5.12 11.776 11.776 11.776 6.656 0 11.776-5.12 11.776-11.776v-29.696h29.696c6.656 0 11.776-5.12 11.776-11.776s-5.632-11.776-12.288-11.776z' fill='%23A8D4FF'/%3E%3Cpath d='M805.66272 620.4416l46.336-46.336 46.34624 46.336-46.34112 46.336zM786.944 831.488l34.816-34.816h-69.632z' fill='%23D9EDFF'/%3E%3Cpath d='M216.064 234.496m-32.768 0a32.768 32.768 0 1 0 65.536 0 32.768 32.768 0 1 0-65.536 0Z' fill='%23D9EDFF'/%3E%3Cpath d='M281.088 794.112l-89.088-89.088c-3.072-3.072-8.192-4.096-12.8-2.56-4.096 2.048-7.168 6.144-7.168 10.752v89.088c0 3.072 1.536 6.144 3.584 8.192 2.048 2.048 5.12 3.584 8.192 3.584h89.088c4.608 0 8.704-3.072 10.752-7.168 1.536-4.096 0.512-9.216-2.56-12.8z m-86.016-3.072v-49.152l49.152 49.152h-49.152z' fill='%23A8D4FF'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: center; } `) this.style(`.FILEUPLOADERmessage { opacity:0; position: fixed; top: 0%; border-radius:3px; text-align: center; min-width: 200px; left: 50%; font-size: 14px; background-color: #c2c2c2; padding: 5px; box-shadow: 0 0px 3px #c2c2c2; z-index: 9999; color: #ffffff; }`) this.style(`.FILEUPLOADERdelIcon {cursor: pointer; margin-left:50px; background-color:#fff; border-radius:50%; margin-bottom:-25px; position: relative; z-index: 10; width: 20px; height: 20px; background-image: url("data:image/svg+xml,%3Csvg t='1686553471493' class='icon' viewBox='0 0 1024 1024' version='1.1' xmlns='http://www.w3.org/2000/svg' p-id='3537' width='20' height='20'%3E%3Cpath d='M872.802928 755.99406 872.864326 755.99406 872.864326 755.624646Z' fill='%23272536' p-id='3538'%3E%3C/path%3E%3Cpath d='M927.846568 511.997953c0-229.315756-186.567139-415.839917-415.838893-415.839917-229.329059 0-415.85322 186.524161-415.85322 415.839917 0 229.300406 186.524161 415.84094 415.85322 415.84094C741.278405 927.838893 927.846568 741.29836 927.846568 511.997953M512.007675 868.171955c-196.375529 0-356.172979-159.827125-356.172979-356.174002 0-196.374506 159.797449-356.157629 356.172979-356.157629 196.34483 0 356.144326 159.783123 356.144326 356.157629C868.152001 708.34483 708.352505 868.171955 512.007675 868.171955' fill='%23272536' p-id='3539'%3E%3C/path%3E%3Cpath d='M682.378947 642.227993 553.797453 513.264806 682.261267 386.229528c11.661597-11.514241 11.749602-30.332842 0.234337-41.995463-11.514241-11.676947-30.362518-11.765975-42.026162-0.222057L511.888971 471.195665 385.223107 344.130711c-11.602246-11.603269-30.393217-11.661597-42.025139-0.059352-11.603269 11.618619-11.603269 30.407544-0.059352 42.011836l126.518508 126.887922L342.137823 639.104863c-11.662621 11.543917-11.780301 30.305213-0.23536 41.96988 5.830799 5.89015 13.429871 8.833179 21.086248 8.833179 7.53972 0 15.136745-2.8847 20.910239-8.569166l127.695311-126.311801L640.293433 684.195827c5.802146 5.8001 13.428847 8.717546 21.056572 8.717546 7.599072 0 15.165398-2.917446 20.968567-8.659217C693.922864 672.681586 693.950494 653.889591 682.378947 642.227993' fill='%23272536' p-id='3540'%3E%3C/path%3E%3C/svg%3E"); } `) this.style(`.FILEUPLOADERdelIcon:hover{background-color:#e5e5e5;}`) this.style( `.FILEUPLOADERaddIcon {width: 100%;text-align: center;font-size: 50px;float: left;}` ) this.style( `.FILEUPLOADERaddFont {margin-top: -5px;font-size: 13px;float: left;width: 100%;text-align: center;}` ) this.style(`.FILEUPLOADERfileListEle {background-color:#f0f0f0;width:570px;margin-top:15px;}`) } style(css) { // 插入 CSS 样式规则到 StyleSheet 中 this.styleSheet.insertRule(css, this.styleNum); this.styleNum++ } dc(element, Class, valueBody) { var Element = document.createElement(element) if (Class != "") { try { Element.classList.add(Class) } catch (e) { //TODO handle the exception } } Element["text"] = function(text) { Element.innerText = text return Element } Element["addClass"] = function(newClass) { Element.classList.add(newClass) return Element } Element["append"] = function(child) { Element.appendChild(child) return Element } Element["tit"] = function(title) { Element.title = title return Element } valueBody = Element return Element } }

问题肯定很多,代码写法肯定问题也有,如果有兴趣可以自己优化一下,毕竟是第一版。

叠个甲,如果你说elementui或者layui也有文件选择器,那么你说得对,我用过,但是我觉得那个耦合太高了,所以我就想只写一个文件选择器,并且能把前端代码量降到最小,全封装到一起,这样方便应该是比自己手搓方便,耦合度也低,但是就是功能不够强大,在js里写前端样式也比较逆天,所以图个乐,小练习。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有