Skip to content

big file upload; slice file upload; support encode slice file ; backend and front-end; 原生js实现前端大文件上传 切片处理

Notifications You must be signed in to change notification settings

Mowmowj/bigFileUpload

Repository files navigation

文件上传

npm run start # 启动前端 npm run server # 启动后端

单个文件上传 form-data

主要是利用js form表单方式进行上传

letformData=newFormData();formData.append('file',_file);formData.append('filename',_file.name);instance.post('/upload_single',formData).then((res)=>{const{ code }=res;if(code===0){alert('file 上传成功');return;}console.log(res);returnPromise.reject(data.codeText);}).catch((e)=>{console.log(e);});

单个文件上传 base64

// 利用FildReader 得到文件的base64/** * FileReader.readAsDataURL()开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的Base64字符串以表示所读取文件的内容。 * **/constgetFileBase64=(file)=>{returnnewPromise((resolve)=>{letfileReader=newFileReader();fileReader.readAsDataURL(file);fileReader.onload=(e)=>{resolve(e.target.result);};});};base64=awaitgetFileBase64(file);upload_input.value='';// 用于初始化inputtry{constdata=awaitinstance.post('/upload_single_base64',{file: encodeURIComponent(base64),// 防止乱码问题 decodeURIComponent 对应filename: file.name,},{headers: {'Content-Type': 'application/x-www-form-urlencoded',},});const{ code }=data;if(code===0){alert('文件上传成功!');}throwdata.codeText;// 抛出异常}catch(e){// 文件上传错误}finally{//}

单个文件上传 图片缩略图, 客户端自定义名字

/** * * @param{} file * @returns * 根据内容生成hash名字 */// SparkMD5 生成HASHconstgetBufferByFile=(file)=>{returnnewPromise((resolve)=>{letfileReader=newFileReader();fileReader.readAsArrayBuffer(file);fileReader.onload=(e)=>{letbuffer=e.target.result;console.log(buffer);constspark=newSparkMD5.ArrayBuffer();spark.append(buffer);constHASH=spark.end();constsuffix=/\.([0-9a-zA-Z]+)$/.exec(file.name)[1];console.log(HASH);resolve({ buffer,HASH, suffix,filename: `${HASH}.${suffix}`,});};});};// 缩略图,可以用base64 来展示constbase64=awaitgetFileBase64(file);const{ filename }=awaitgetFileBase64(_file);letformData=newFormData();formData.append('file',_file);formData.append('filename',filename);// 处理名字,服务端不提供名字编译instance.post('/upload_single_name',formData).then((res)=>{const{ code }=res;if(code===0){alert('file 上传成功');return;}console.log(res);returnPromise.reject(data.codeText);}).catch((e)=>{console.log(e);});});

单个文件上传 进度条管控

上传进度,主要是靠axios中回调

try{letformData=newFormData();formData.append('file',file);formData.append('filename',file.filename);constdata=awaitinstance.post('/upload_single',formData,{// onPuloadProgress; 变化来更新进度onUploadProgress: (e)=>{console.log(e);const{ loaded, total }=e;console.log(`${(loaded/total)*100}%`,' `${loaded/total*100}%`');upload_progress.style.display='block';upload_progrees_value.style.width=`${(loaded/total)*100}%`;},});const{ code }=data;if(code===0){upload_progrees_value.style.width=`100%`;alert('文件上传成功!');return;}throwdata.codeText;}catch(e){//console.log(e);alert('文件上传失败');}finally{this.value='';}

多个文件上传 进度条管控

主要是对上传列表做一个遍历上传。 结合Promise.all() 表示是否全部上传成功!

const_files=files.map((item)=>{constfm=newFormData();constcurLi=upload_list_arr.find((liBox)=>liBox.getAttribute('key')===item.key);constcurSpan=curLi ? curLi.querySelector('span:nth-last-child(1)') : null;fm.append('file',item.file);fm.append('filename',item.filename);returninstance.post('/upload_single',fm,{onUploadProgress(e){// 监听每一个上传进度const{ loaded, total }=e;constprogress=`${((loaded/total)*100).toFixed(2)}%`;if(curSpan){curSpan.innerText=progress;}},}).then((data)=>{const{ code }=data;if(code===0){if(curSpan){curSpan.innerText='100%';}returnPromise.resolve(data);}returnPromise.reject(data.codeText);});});Promise.all(_files).then((res)=>{console.log(res);alert('上传成功');});

拖拽上传3

拖拽上传没有什么特殊的, 值得注意的是, drop 中的事件参数回携带 dataTransfer, 里面包含着 files。,提取出来,走上传即可!

// 拖拽进入dragBox.addEventListener('dragenter',function(e){// console.log('拖拽进入')e.preventDefault();this.style.border='1px solid red';});// 拖拽放下dragBox.addEventListener('drop',function(e){e.preventDefault();this.style.border='';const{dataTransfer: { files },}=e;constfile=files[0];uploadFile(file);});dragBox.addEventListener('dragover',function(e){e.preventDefault();});

切片上传

切片上传相对于上面,复杂一些, 当然也没有想象中的难!

  1. 上传文件
  2. 利用Bole.prototype.slice() 方法对文件进行切片, 对每一个文件进行HASH 唯一标识
  3. 从服务器获取已经上传的切片,判断是否有些切片已经上传
  4. 上传切片
  5. 上传完切片,通知服务端合并切片
upload_button_upload.addEventListener('click',asyncfunction(){// 点击开始上传letchunkList=[];letalreadyChunkList=[];console.log(_file);letmaxSize=1024*1024;letmaxCount=Math.ceil(_file.size/maxSize);// 最大允许分割的切片数量为30letindex=0;if(!_file)returnalert('请先选择图片');const{HASH, suffix }=awaitchangeBuffer(_file);// 判断当前文件可以切出多少切片if(maxCount>10){// 如果切片数量大于最大值maxSize=_file.size/10;// 则改变切片大小maxCount=10;}console.log(maxCount,'maxCount');console.log(maxSize,'maxSize');while(index<maxCount){chunkList.push({file: _file.slice(index*maxSize,(index+1)*maxSize),filename: `${HASH}_${index+1}.${suffix}`,});index++;}// 先获取已经上传的切片constdata=awaitinstance.post('/upload_already',{HASH: HASH,},{headers: {'Content-Type': 'application/x-www-form-urlencoded',},});index=0constcomplate=async()=>{index++;letprogress=`(${index}/${maxCount})%`// 进度条if(index>=maxCount){console.log('ok, 切片完成')}}const{ fileList }=data;alreadyChunkList=fileListconsole.log(chunkList,'chunkList');chunkList=chunkList.map((item)=>{if(alreadyChunkList.length>0&&alreadyChunkList.includes(item.filename)){debugger// 表示切片已经存在complate()return;}constfm=newFormData();fm.append('file',item.file);fm.append('filename',item.filename);returnnewPromise((sovle)=>{instance.post('/upload_chunk',fm).then(()=>{complate()sovle();}).catch(()=>{//});});});Promise.all(chunkList).then(()=>{instance.post('/upload_merge',{HASH: HASH,count: maxCount,},{headers: {'Content-Type': 'application/x-www-form-urlencoded',},}).then((res)=>{console.log('ok');});});});

About

big file upload; slice file upload; support encode slice file ; backend and front-end; 原生js实现前端大文件上传 切片处理

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published